Skip to content

Commit

Permalink
frontend: Add special handling for self calls
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Oct 15, 2024
1 parent b1fe4fe commit 414f132
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 60 deletions.
6 changes: 3 additions & 3 deletions dora-frontend/src/program_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> {
}
}

fn visit_type_alias(&mut self, node: &Arc<ast::TypeAlias>) {
fn visit_type_alias(&mut self, node: &Arc<ast::Alias>) {
let modifiers = check_modifiers(self.sa, self.file_id, &node.modifiers, &[Annotation::Pub]);

let parsed_ty = if let Some(ref ty) = node.ty {
Expand Down Expand Up @@ -978,7 +978,7 @@ fn find_elements_in_trait(
}
}

ast::ElemData::TypeAlias(ref node) => {
ast::ElemData::Alias(ref node) => {
let modifiers = check_modifiers(sa, file_id, &node.modifiers, &[]);

let name = ensure_name(sa, &node.name);
Expand Down Expand Up @@ -1124,7 +1124,7 @@ fn find_elements_in_impl(
methods.push(fct_id);
}

ast::ElemData::TypeAlias(ref node) => {
ast::ElemData::Alias(ref node) => {
let modifiers = check_modifiers(sa, file_id, &node.modifiers, &[]);

let name = ensure_name(sa, &node.name);
Expand Down
4 changes: 2 additions & 2 deletions dora-frontend/src/sema/aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub struct AliasDefinition {
pub module_id: ModuleDefinitionId,
pub file_id: SourceFileId,
pub parent: AliasParent,
pub node: Arc<ast::TypeAlias>,
pub node: Arc<ast::Alias>,
pub modifiers: ParsedModifierList,
pub name: Name,
pub parsed_ty: Option<ParsedType>,
Expand All @@ -75,7 +75,7 @@ impl AliasDefinition {
module_id: ModuleDefinitionId,
file_id: SourceFileId,
parent: AliasParent,
node: &Arc<ast::TypeAlias>,
node: &Arc<ast::Alias>,
modifiers: ParsedModifierList,
name: Name,
type_param_definition: Rc<TypeParamDefinition>,
Expand Down
6 changes: 6 additions & 0 deletions dora-frontend/src/sema/type_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ impl TypeParamDefinition {
.map(|b| b.trait_ty().expect("trait type expected"))
}

pub fn bounds_for_self<'a>(&'a self) -> impl Iterator<Item = TraitType> + 'a {
self.bounds()
.filter(move |b| b.ty() == SourceType::This && b.trait_ty().is_some())
.map(|b| b.trait_ty().expect("trait type expected"))
}

pub fn type_param_count(&self) -> usize {
self.container_type_params + self.type_params.len()
}
Expand Down
89 changes: 83 additions & 6 deletions dora-frontend/src/typeck/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ use crate::typeck::{
find_method_call_candidates, read_path_expr, MethodLookup, TypeCheck,
};
use crate::typeparamck::{self, ErrorReporting};
use crate::{specialize_type, ty::error as ty_error, ErrorMessage, SourceType, SourceTypeArray};
use crate::{
empty_sta, specialize_type, ty::error as ty_error, ErrorMessage, SourceType, SourceTypeArray,
};

pub(super) fn check_expr_call(
ck: &mut TypeCheck,
Expand Down Expand Up @@ -330,7 +332,17 @@ fn check_expr_call_method(
) -> SourceType {
if let SourceType::TypeParam(id) = object_type {
assert_eq!(fct_type_params.len(), 0);
return check_expr_call_generic(ck, e, id, method_name, arg_types);
return check_expr_call_generic_type_param(
ck,
e,
SourceType::TypeParam(id),
id,
method_name,
arg_types,
);
} else if object_type.is_self() {
assert_eq!(fct_type_params.len(), 0);
return check_expr_call_self(ck, e, method_name, arg_types);
}

if object_type.is_error() {
Expand Down Expand Up @@ -624,14 +636,79 @@ fn check_expr_call_class(
cls_ty
}

fn check_expr_call_generic(
fn check_expr_call_self(
ck: &mut TypeCheck,
e: &ast::ExprCallType,
tp_id: TypeParamId,
name: String,
arg_types: &[SourceType],
args: &[SourceType],
) -> SourceType {
check_expr_call_generic_type_param(ck, e, SourceType::TypeParam(tp_id), tp_id, name, arg_types)
let mut matched_methods = Vec::new();
let interned_name = ck.sa.interner.intern(&name);

{
let trait_id = ck.parent.trait_id().expect("trait expected");
let trait_ = ck.sa.trait_(trait_id);

if let Some(trait_method_id) = trait_.get_method(interned_name, false) {
matched_methods.push(trait_method_id);
}
}

for trait_ty in ck.type_param_definition.bounds_for_self() {
let trait_ = ck.sa.trait_(trait_ty.trait_id);

if let Some(trait_method_id) = trait_.get_method(interned_name, false) {
matched_methods.push(trait_method_id);
}
}

if matched_methods.len() == 1 {
let trait_method_id = matched_methods.pop().expect("missing element");
let trait_type_params = empty_sta();

let trait_method = ck.sa.fct(trait_method_id);
let return_type = trait_method.return_type();

ck.analysis.set_ty(e.id, return_type.clone());

// This should likely become a generic call in the future, once
// the default trait method isn't copied into the impl method anymore.
let call_type =
CallType::Method(SourceType::This, trait_method_id, trait_type_params.clone());
ck.analysis.map_calls.insert(e.id, Arc::new(call_type));

if !args_compatible_fct(
ck.sa,
trait_method,
args,
&trait_type_params,
Some(SourceType::This),
) {
let trait_params = trait_method
.params_without_self()
.iter()
.map(|a| specialize_type(ck.sa, a.ty(), &trait_type_params))
.map(|a| ck.ty_name(&a))
.collect::<Vec<String>>();
let param_names = args.iter().map(|a| ck.ty_name(a)).collect::<Vec<String>>();
let msg = ErrorMessage::ParamTypesIncompatible(name, trait_params, param_names);
ck.sa.report(ck.file_id, e.span, msg);
}

return_type
} else {
let param_names = args.iter().map(|a| ck.ty_name(a)).collect::<Vec<String>>();
let msg = if matched_methods.is_empty() {
ErrorMessage::UnknownMethod("Self".into(), name, param_names)
} else {
ErrorMessage::MultipleCandidatesForMethod("Self".into(), name, param_names)
};

ck.sa.report(ck.file_id, e.span, msg);
ck.analysis.set_ty(e.id, ty_error());

ty_error()
}
}

fn check_expr_call_generic_type_param(
Expand Down
35 changes: 2 additions & 33 deletions dora-frontend/src/typeck/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::error::msg::ErrorMessage;
use crate::interner::Name;
use crate::sema::{
extension_matches, impl_matches, Candidate, FctDefinitionId, FctParent, Sema, SourceFileId,
TraitDefinitionId, TypeParamDefinition,
TypeParamDefinition,
};
use crate::typeck::function::args_compatible_fct;
use crate::typeparamck::{self, ErrorReporting};
Expand Down Expand Up @@ -55,7 +55,6 @@ impl MethodLookupResult {
enum LookupKind {
Method(SourceType),
Static(SourceType),
Self_(TraitDefinitionId),
Callee(FctDefinitionId),
}

Expand Down Expand Up @@ -105,18 +104,7 @@ impl<'a> MethodLookup<'a> {
}

pub fn method(mut self, obj: SourceType) -> MethodLookup<'a> {
let kind = match obj {
SourceType::This => {
let parent = self.fct_parent.clone().expect("parent missing");
match parent {
FctParent::Trait(id) => LookupKind::Self_(id),
_ => unreachable!(),
}
}
_ => LookupKind::Method(obj),
};

self.kind = Some(kind);
self.kind = Some(LookupKind::Method(obj));

self
}
Expand Down Expand Up @@ -164,11 +152,6 @@ impl<'a> MethodLookup<'a> {
self.find_method(&mut result, obj.clone(), name, false)
}

LookupKind::Self_(trait_id) => {
let name = self.name.expect("name not set");
self.find_method_in_trait(trait_id, name, false)
}

LookupKind::Static(ref obj) => {
let name = self.name.expect("name not set");
self.find_method(&mut result, obj.clone(), name, true)
Expand Down Expand Up @@ -200,10 +183,6 @@ impl<'a> MethodLookup<'a> {
}
}

LookupKind::Self_(..) => {
ErrorMessage::UnknownMethod("Self".into(), name, param_names)
}

LookupKind::Static(ref obj) => {
let type_name = self.ty_name(obj);
ErrorMessage::UnknownStaticMethod(type_name, name, param_names)
Expand Down Expand Up @@ -303,16 +282,6 @@ impl<'a> MethodLookup<'a> {
}
}

fn find_method_in_trait(
&mut self,
trait_id: TraitDefinitionId,
name: Name,
is_static: bool,
) -> Option<FctDefinitionId> {
let trait_ = self.sa.trait_(trait_id);
trait_.get_method(name, is_static)
}

fn check_tps(&self, specified_tps: &TypeParamDefinition, tps: &SourceTypeArray) -> bool {
let error = if self.report_errors {
ErrorReporting::Yes(self.file, self.span.expect("no pos"))
Expand Down
6 changes: 3 additions & 3 deletions dora-parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub enum ElemData {
Module(Arc<Module>),
Use(Arc<Use>),
Extern(Arc<ExternPackage>),
TypeAlias(Arc<TypeAlias>),
Alias(Arc<Alias>),
Error { id: NodeId, span: Span },
}

Expand All @@ -119,7 +119,7 @@ impl ElemData {
ElemData::Module(ref node) => node.span,
ElemData::Use(ref node) => node.span,
ElemData::Extern(ref node) => node.span,
ElemData::TypeAlias(ref node) => node.span,
ElemData::Alias(ref node) => node.span,
ElemData::Error { span, .. } => span.clone(),
}
}
Expand Down Expand Up @@ -584,7 +584,7 @@ pub struct Trait {
}

#[derive(Clone, Debug)]
pub struct TypeAlias {
pub struct Alias {
pub id: NodeId,
pub span: Span,
pub green: GreenNode,
Expand Down
4 changes: 2 additions & 2 deletions dora-parser/src/ast/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl AstDumper {
ElemData::Module(ref node) => self.dump_module(node),
ElemData::Use(ref node) => self.dump_use(node),
ElemData::Extern(ref node) => self.dump_extern(node),
ElemData::TypeAlias(ref node) => self.dump_associated_type(node),
ElemData::Alias(ref node) => self.dump_associated_type(node),
ElemData::Error { id, span } => {
dump!(self, "error @ {} {}", span, id);
}
Expand Down Expand Up @@ -183,7 +183,7 @@ impl AstDumper {
});
}

fn dump_associated_type(&mut self, t: &TypeAlias) {
fn dump_associated_type(&mut self, t: &Alias) {
dump!(self, "trait @ {} {}", t.span, t.id);
self.indent(|d| {
d.dump_ident(&t.name);
Expand Down
6 changes: 3 additions & 3 deletions dora-parser/src/ast/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub trait Visitor: Sized {
walk_expr(self, e);
}

fn visit_type_alias(&mut self, e: &Arc<TypeAlias>) {
fn visit_type_alias(&mut self, e: &Arc<Alias>) {
walk_type_alias(self, e);
}
}
Expand All @@ -105,7 +105,7 @@ pub fn walk_elem<V: Visitor>(v: &mut V, e: &ElemData) {
ElemData::Module(ref e) => v.visit_module(e),
ElemData::Use(ref i) => v.visit_use(i),
ElemData::Extern(ref stmt) => v.visit_extern(stmt),
ElemData::TypeAlias(ref node) => v.visit_type_alias(node),
ElemData::Alias(ref node) => v.visit_type_alias(node),
ElemData::Error { .. } => {}
}
}
Expand Down Expand Up @@ -161,7 +161,7 @@ pub fn walk_extern<V: Visitor>(_v: &mut V, _use: &Arc<ExternPackage>) {
// nothing to do
}

pub fn walk_type_alias<V: Visitor>(_v: &mut V, _node: &Arc<TypeAlias>) {
pub fn walk_type_alias<V: Visitor>(_v: &mut V, _node: &Arc<Alias>) {
// nothing to do
}

Expand Down
12 changes: 6 additions & 6 deletions dora-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ impl Parser {
}

TYPE_KW => {
let type_alias = self.parse_type_alias(modifiers);
Arc::new(ElemData::TypeAlias(type_alias))
let alias = self.parse_alias(modifiers);
Arc::new(ElemData::Alias(alias))
}

_ => {
Expand Down Expand Up @@ -567,7 +567,7 @@ impl Parser {
})
}

fn parse_type_alias(&mut self, modifiers: Option<ModifierList>) -> Arc<TypeAlias> {
fn parse_alias(&mut self, modifiers: Option<ModifierList>) -> Arc<Alias> {
self.start_node();
self.assert(TYPE_KW);
let name = self.expect_identifier();
Expand All @@ -587,9 +587,9 @@ impl Parser {
};
self.expect(SEMICOLON);

let green = self.builder.finish_node(TYPE_ALIAS);
let green = self.builder.finish_node(ALIAS);

Arc::new(TypeAlias {
Arc::new(Alias {
id: self.new_node_id(),
green,
span: self.finish_node(),
Expand Down Expand Up @@ -3882,7 +3882,7 @@ mod tests {
}

#[test]
fn parse_type_alias_in_trait() {
fn parse_alias_in_trait() {
parse(
"trait Foo {
type MY_TYPE;
Expand Down
3 changes: 1 addition & 2 deletions dora-parser/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ pub enum TokenKind {
// Syntax tree nodes
SOURCE_FILE,

ALIAS,
FN,
STRUCT,
STRUCT_FIELD,
Expand Down Expand Up @@ -240,7 +239,7 @@ pub enum TokenKind {
TYPE_LIST,
ARG_LIST,
PATTERN_LIST,
TYPE_ALIAS,
ALIAS,

PARAM_LIST,

Expand Down

0 comments on commit 414f132

Please sign in to comment.