diff --git a/dora-bytecode/src/program.rs b/dora-bytecode/src/program.rs index 2de0ab70f..ad4d384b8 100644 --- a/dora-bytecode/src/program.rs +++ b/dora-bytecode/src/program.rs @@ -42,6 +42,7 @@ pub struct FunctionData { pub is_force_inline: bool, pub is_never_inline: bool, pub bytecode: Option, + pub trait_method_impl: Option, } #[derive(Debug, Decode, Encode)] diff --git a/dora-frontend/src/exhaustiveness.rs b/dora-frontend/src/exhaustiveness.rs index db47ef61e..ebe1d35f9 100644 --- a/dora-frontend/src/exhaustiveness.rs +++ b/dora-frontend/src/exhaustiveness.rs @@ -19,7 +19,7 @@ pub fn check(sa: &Sema) { file_id: fct.file_id, analysis: fct.analysis(), }; - visit::walk_fct(&mut visitor, &fct.ast); + visit::walk_fct(&mut visitor, fct.ast().as_ref().expect("body expected")); } } } diff --git a/dora-frontend/src/generator.rs b/dora-frontend/src/generator.rs index b0175fdd7..cb0dcacae 100644 --- a/dora-frontend/src/generator.rs +++ b/dora-frontend/src/generator.rs @@ -65,7 +65,7 @@ pub fn generate_fct(sa: &Sema, fct: &FctDefinition, src: &AnalysisData) -> Bytec unit_register: None, entered_contexts: Vec::new(), }; - ast_bytecode_generator.generate_fct(&fct.ast) + ast_bytecode_generator.generate_fct(fct.ast().expect("body expected")) } pub fn generate_global_initializer( diff --git a/dora-frontend/src/impldefck.rs b/dora-frontend/src/impldefck.rs index b47ea6062..c7c0c499f 100644 --- a/dora-frontend/src/impldefck.rs +++ b/dora-frontend/src/impldefck.rs @@ -110,20 +110,23 @@ pub fn check_definition_against_trait(sa: &mut Sema) { let return_type = trait_method.return_type(); let return_type = replace_type(sa, return_type, None, self_ty.clone()); - let fct = FctDefinition::new( + let fct = FctDefinition::new_no_source( impl_.package_id, impl_.module_id, impl_.file_id, - &trait_method.ast, + trait_method.declaration_span, + trait_method.span, + trait_method.ast(), ParsedModifierList::default(), trait_method.name, trait_method .type_param_definition() .clone_with_new_parent(impl_.type_param_definition().to_owned()), params, + return_type, FctParent::Impl(impl_.id()), ); - fct.return_type.set_ty(return_type); + assert!(fct.trait_method_impl.set(*trait_method_id).is_ok()); new_fcts.push(fct); } } @@ -168,12 +171,13 @@ fn check_impl_methods( sa.report( impl_method.file_id, - impl_method.ast.span, + impl_method.span, ErrorMessage::AliasExists(method_name, existing_fct.span), ); } remaining_trait_methods.remove(&trait_method_id); + assert!(impl_method.trait_method_impl.set(trait_method_id).is_ok()); let trait_method = sa.fct(trait_method_id); diff --git a/dora-frontend/src/lib.rs b/dora-frontend/src/lib.rs index b8de63773..c6dc7cfd4 100644 --- a/dora-frontend/src/lib.rs +++ b/dora-frontend/src/lib.rs @@ -111,8 +111,8 @@ pub fn emit_ast(sa: &Sema, filter: &str) { for (_id, fct) in sa.fcts.iter() { let fct_name = fct.display_name(sa); - if fct_pattern_match(&fct_name, filter) { - ast::dump::dump_fct(&fct.ast); + if fct_pattern_match(&fct_name, filter) && fct.has_body() { + ast::dump::dump_fct(fct.ast().expect("body expected")); } } } @@ -172,7 +172,8 @@ fn fct_pattern_match(name: &str, pattern: &str) -> bool { fn internalck(sa: &Sema) { for (_id, fct) in sa.fcts.iter() { - if !fct.has_body() && !fct.in_trait() && !fct.is_internal { + if !fct.has_body() && !fct.in_trait() && !fct.is_internal && !fct.use_trait_default_impl(sa) + { sa.report(fct.file_id, fct.span, ErrorMessage::MissingFctBody); } } diff --git a/dora-frontend/src/program_emitter.rs b/dora-frontend/src/program_emitter.rs index 437b3f43b..835c216d4 100644 --- a/dora-frontend/src/program_emitter.rs +++ b/dora-frontend/src/program_emitter.rs @@ -212,6 +212,11 @@ fn create_functions(sa: &Sema, e: &mut Emitter) -> Vec { is_force_inline: fct.is_force_inline, is_never_inline: fct.is_never_inline, bytecode: fct.bytecode.get().cloned(), + trait_method_impl: fct + .trait_method_impl + .get() + .cloned() + .map(|id| convert_function_id(id)), }) } @@ -241,6 +246,7 @@ fn create_functions(sa: &Sema, e: &mut Emitter) -> Vec { is_force_inline: false, is_never_inline: false, bytecode: Some(global.bytecode().clone()), + trait_method_impl: None, }); e.global_initializer.insert(global.id(), fct_id); diff --git a/dora-frontend/src/sema/functions.rs b/dora-frontend/src/sema/functions.rs index 9bc39c292..08fddfd90 100644 --- a/dora-frontend/src/sema/functions.rs +++ b/dora-frontend/src/sema/functions.rs @@ -25,7 +25,7 @@ pub struct FctDefinition { pub package_id: PackageDefinitionId, pub module_id: ModuleDefinitionId, pub file_id: SourceFileId, - pub ast: Arc, + pub ast: Option>, pub declaration_span: Span, pub span: Span, pub name: Name, @@ -46,6 +46,7 @@ pub struct FctDefinition { pub container_type_params: OnceCell, pub bytecode: OnceCell, pub intrinsic: OnceCell, + pub trait_method_impl: OnceCell, } impl FctDefinition { @@ -73,7 +74,7 @@ impl FctDefinition { file_id, declaration_span: ast.declaration_span, span: ast.span, - ast: ast.clone(), + ast: Some(ast.clone()), name, params, return_type, @@ -90,6 +91,49 @@ impl FctDefinition { container_type_params: OnceCell::new(), bytecode: OnceCell::new(), intrinsic: OnceCell::new(), + trait_method_impl: OnceCell::new(), + } + } + + pub(crate) fn new_no_source( + package_id: PackageDefinitionId, + module_id: ModuleDefinitionId, + file_id: SourceFileId, + declaration_span: Span, + span: Span, + ast: Option<&Arc>, + modifiers: ParsedModifierList, + name: Name, + type_params: Rc, + params: Params, + return_type: SourceType, + parent: FctParent, + ) -> FctDefinition { + FctDefinition { + id: None, + package_id, + module_id, + file_id, + declaration_span: declaration_span, + span: span, + ast: ast.cloned(), + name, + params, + return_type: ParsedType::new_ty(return_type), + parent, + is_optimize_immediately: modifiers.is_optimize_immediately, + visibility: modifiers.visibility(), + is_static: modifiers.is_static, + is_test: modifiers.is_test, + is_internal: modifiers.is_internal, + is_force_inline: modifiers.is_force_inline, + is_never_inline: modifiers.is_never_inline, + analysis: OnceCell::new(), + type_param_definition: type_params, + container_type_params: OnceCell::new(), + bytecode: OnceCell::new(), + intrinsic: OnceCell::new(), + trait_method_impl: OnceCell::new(), } } @@ -118,6 +162,21 @@ impl FctDefinition { } } + pub fn use_trait_default_impl(&self, sa: &Sema) -> bool { + if self.parent.is_impl() { + let trait_method_id = self + .trait_method_impl + .get() + .cloned() + .expect("missing trait method"); + + let trait_method = sa.fct(trait_method_id); + trait_method.has_body() + } else { + false + } + } + pub fn is_self_allowed(&self) -> bool { match self.parent { FctParent::Impl(..) | FctParent::Trait(..) | FctParent::Extension(..) => true, @@ -169,11 +228,18 @@ impl FctDefinition { } pub fn has_body(&self) -> bool { - self.ast.block.is_some() + self.ast + .as_ref() + .map(|a| a.block.is_some()) + .unwrap_or(false) + } + + pub fn ast(&self) -> Option<&Arc> { + self.ast.as_ref() } pub fn is_lambda(&self) -> bool { - self.ast.kind.is_lambda() + self.parent.is_function() } pub fn span(&self) -> Span { @@ -315,6 +381,13 @@ impl FctParent { } } + pub fn is_function(&self) -> bool { + match self { + &FctParent::Function => true, + _ => false, + } + } + pub fn is_impl(&self) -> bool { match self { &FctParent::Impl(..) => true, diff --git a/dora-frontend/src/typeck.rs b/dora-frontend/src/typeck.rs index f1e734298..d19e0c890 100644 --- a/dora-frontend/src/typeck.rs +++ b/dora-frontend/src/typeck.rs @@ -118,7 +118,7 @@ fn check_function( element: fct, }; - typeck.check_fct(&fct.ast); + typeck.check_fct(fct.ast().expect("body expected")); assert!(fct.analysis.set(analysis).is_ok()); } diff --git a/dora-runtime/src/cannon/codegen.rs b/dora-runtime/src/cannon/codegen.rs index 4b8d7ad91..458e7f60a 100644 --- a/dora-runtime/src/cannon/codegen.rs +++ b/dora-runtime/src/cannon/codegen.rs @@ -55,6 +55,7 @@ pub struct CannonCodeGen<'a> { emit_code_comments: bool, type_params: BytecodeTypeArray, + specialize_self: Option, offset_to_address: HashMap, offset_to_label: HashMap, @@ -97,6 +98,7 @@ impl<'a> CannonCodeGen<'a> { bytecode: compilation_data.bytecode_fct, emit_code_comments: compilation_data.emit_code_comments, type_params: compilation_data.type_params, + specialize_self: compilation_data.specialize_self, offset_to_address: HashMap::new(), offset_to_label: HashMap::new(), current_offset: BytecodeOffset(0), @@ -3932,11 +3934,21 @@ impl<'a> CannonCodeGen<'a> { } fn specialize_ty(&self, ty: BytecodeType) -> BytecodeType { - specialize_ty(self.vm, None, ty, &self.type_params) + specialize_ty( + self.vm, + self.specialize_self.as_ref(), + ty, + &self.type_params, + ) } fn specialize_ty_array(&self, types: &BytecodeTypeArray) -> BytecodeTypeArray { - specialize_ty_array(self.vm, None, types, &self.type_params) + specialize_ty_array( + self.vm, + self.specialize_self.as_ref(), + types, + &self.type_params, + ) } fn register_offset(&self, reg: Register) -> i32 { diff --git a/dora-runtime/src/compiler/aot.rs b/dora-runtime/src/compiler/aot.rs index a9f6b8547..3e0480cd7 100644 --- a/dora-runtime/src/compiler/aot.rs +++ b/dora-runtime/src/compiler/aot.rs @@ -18,7 +18,7 @@ use crate::vm::{ specialize_bty, specialize_bty_array, BytecodeTypeExt, Code, LazyCompilationSite, ShapeKind, VM, }; -use crate::Shape; +use crate::{get_bytecode, Shape}; pub fn compile_boots_aot(vm: &VM) { if vm.has_boots() { @@ -247,8 +247,8 @@ impl<'a> TransitiveClosureComputation<'a> { fn trace(&mut self, fct_id: FunctionId, type_params: BytecodeTypeArray) { let fct = &self.vm.fct(fct_id); - if let Some(ref bytecode_function) = fct.bytecode { - self.iterate_bytecode(bytecode_function, type_params); + if let Some((bytecode_function, specialize_self)) = get_bytecode(self.vm, fct) { + self.iterate_bytecode(bytecode_function, type_params, specialize_self); } } @@ -256,6 +256,7 @@ impl<'a> TransitiveClosureComputation<'a> { &mut self, bytecode_function: &BytecodeFunction, type_params: BytecodeTypeArray, + _specialize_self: Option, ) { let reader = BytecodeReader::new(bytecode_function.code()); @@ -548,6 +549,24 @@ fn prepare_lazy_call_sites( type_params, const_pool_offset_from_ra, } => { + let target = ctc + .function_addresses + .get(&(*fct_id, type_params.clone())) + .cloned(); + + if target.is_none() { + println!( + "code = {:?} {}", + code.descriptor(), + display_fct(&_vm.program, *fct_id) + ); + println!( + " calls {} with {:?}", + display_fct(&_vm.program, *fct_id), + type_params + ); + println!("offset = {}", offset); + } let target = ctc .function_addresses .get(&(*fct_id, type_params.clone())) diff --git a/dora-runtime/src/compiler/codegen.rs b/dora-runtime/src/compiler/codegen.rs index 4cb311659..867c40943 100644 --- a/dora-runtime/src/compiler/codegen.rs +++ b/dora-runtime/src/compiler/codegen.rs @@ -11,7 +11,7 @@ use crate::os; use crate::vm::{install_code, Code, CodeDescriptor, CodeId, CodeKind, Compiler, VM}; use dora_bytecode::{ display_fct, display_ty_array, display_ty_without_type_params, dump_stdout, BytecodeFunction, - BytecodeType, BytecodeTypeArray, FunctionData, FunctionId, Location, + BytecodeType, BytecodeTypeArray, FunctionData, FunctionId, FunctionKind, Location, }; #[derive(Clone, Copy)] @@ -40,7 +40,7 @@ pub fn compile_fct_jit(vm: &VM, fct_id: FunctionId, type_params: &BytecodeTypeAr let program_fct = vm.fct(fct_id); let params = BytecodeTypeArray::new(program_fct.params.clone()); - let bytecode_fct = program_fct.bytecode.as_ref().expect("missing bytecode"); + let (bytecode_fct, specialize_self) = get_bytecode(vm, program_fct).expect("missing bytecode"); assert_ne!(Some(program_fct.package_id), vm.program.boots_package_id); let compiler = select_compiler(vm, fct_id, program_fct); @@ -60,6 +60,7 @@ pub fn compile_fct_jit(vm: &VM, fct_id: FunctionId, type_params: &BytecodeTypeAr program_fct.return_type.clone(), bytecode_fct, type_params, + specialize_self, compiler, vm.flags.emit_compiler, CompilationMode::Jit, @@ -81,7 +82,7 @@ pub fn compile_fct_aot( ) -> (CodeId, Arc) { let program_fct = vm.fct(fct_id); let params = BytecodeTypeArray::new(program_fct.params.clone()); - let bytecode_fct = program_fct.bytecode.as_ref().expect("missing bytecode"); + let (bytecode_fct, specialize_self) = get_bytecode(vm, program_fct).expect("missing bytecode"); let (code_id, code) = compile_fct_to_code( vm, @@ -91,6 +92,7 @@ pub fn compile_fct_aot( program_fct.return_type.clone(), bytecode_fct, type_params, + specialize_self, compiler, false, mode, @@ -98,6 +100,31 @@ pub fn compile_fct_aot( (code_id, code) } +pub fn get_bytecode<'a>( + vm: &'a VM, + program_fct: &'a FunctionData, +) -> Option<(&'a BytecodeFunction, Option)> { + match program_fct.bytecode.as_ref() { + Some(bytecode_fct) => Some((bytecode_fct, None)), + None => { + let trait_method_id = program_fct.trait_method_impl?; + let trait_method = vm.fct(trait_method_id); + + let program_fct_impl_id = match program_fct.kind { + FunctionKind::Impl(impl_id) => impl_id, + _ => unreachable!(), + }; + + let bytecode_fct = trait_method.bytecode.as_ref()?; + + let program_fct_impl = vm.impl_(program_fct_impl_id); + let specialize_self = program_fct_impl.extended_ty.clone(); + + Some((bytecode_fct, Some(specialize_self))) + } + } +} + pub(super) fn compile_fct_to_code( vm: &VM, fct_id: FunctionId, @@ -106,6 +133,7 @@ pub(super) fn compile_fct_to_code( return_type: BytecodeType, bytecode_fct: &BytecodeFunction, type_params: &BytecodeTypeArray, + specialize_self: Option, compiler: CompilerInvocation, emit_compiler: bool, mode: CompilationMode, @@ -118,6 +146,7 @@ pub(super) fn compile_fct_to_code( return_type, bytecode_fct, type_params, + specialize_self, compiler, emit_compiler, mode, @@ -149,6 +178,7 @@ fn compile_fct_to_descriptor( return_type: BytecodeType, bytecode_fct: &BytecodeFunction, type_params: &BytecodeTypeArray, + specialize_self: Option, compiler: CompilerInvocation, emit_compiler: bool, mode: CompilationMode, @@ -194,6 +224,7 @@ fn compile_fct_to_descriptor( return_type, fct_id, type_params: type_params.clone(), + specialize_self, loc: program_fct.loc, emit_debug, @@ -438,6 +469,7 @@ pub struct CompilationData<'a> { pub return_type: BytecodeType, pub fct_id: FunctionId, pub type_params: BytecodeTypeArray, + pub specialize_self: Option, pub loc: Location, pub emit_debug: bool, diff --git a/dora-runtime/src/compiler/trait_object_thunk.rs b/dora-runtime/src/compiler/trait_object_thunk.rs index 4257765b5..526d486cb 100644 --- a/dora-runtime/src/compiler/trait_object_thunk.rs +++ b/dora-runtime/src/compiler/trait_object_thunk.rs @@ -138,6 +138,7 @@ fn compile_thunk_to_code( bytecode_fct.return_type().clone(), &bytecode_fct, type_params, + None, compiler, emit_compiler, mode, diff --git a/dora-runtime/src/lib.rs b/dora-runtime/src/lib.rs index c0c481a88..635af9837 100644 --- a/dora-runtime/src/lib.rs +++ b/dora-runtime/src/lib.rs @@ -32,6 +32,7 @@ mod timer; mod utils; pub mod vm; +use compiler::codegen::get_bytecode; use gc::Address; use shape::{Shape, ShapeVisitor}; pub use vm::VM; diff --git a/dora-runtime/src/vm/specialize.rs b/dora-runtime/src/vm/specialize.rs index 91d0c2d92..d7be0ed95 100644 --- a/dora-runtime/src/vm/specialize.rs +++ b/dora-runtime/src/vm/specialize.rs @@ -696,7 +696,9 @@ pub fn specialize_ty( specialize_ty(vm, self_ty, impl_alias_ty, &bindings) } - BytecodeType::TypeAlias(..) | BytecodeType::Assoc(..) | BytecodeType::This => { + BytecodeType::This => self_ty.expect("unexpected Self").clone(), + + BytecodeType::TypeAlias(..) | BytecodeType::Assoc(..) => { unreachable!() }