Raise the priority of traits in method search

This commit is contained in:
Shunsuke Shibayama 2022-10-06 09:16:14 +09:00
parent 59f6046916
commit e89bb869bf
4 changed files with 47 additions and 37 deletions

View file

@ -126,25 +126,20 @@ impl Context {
} }
} }
for (trait_method, vi) in ctx.decls.iter() { for (trait_method, vi) in ctx.decls.iter() {
if let Some(types) = self.method_to_types.get_mut(trait_method.inspect()) { if let Some(types) = self.method_to_traits.get_mut(trait_method.inspect()) {
types.push(MethodType::new(t.clone(), vi.t.clone())); types.push(MethodType::new(t.clone(), vi.t.clone()));
} else { } else {
self.method_to_types.insert( self.method_to_traits.insert(
trait_method.inspect().clone(), trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())], vec![MethodType::new(t.clone(), vi.t.clone())],
); );
} }
} }
for (class_method, vi) in ctx.locals.iter() { for (class_method, vi) in ctx.locals.iter() {
if let Some(mut types) = self.method_to_types.remove(class_method.inspect()) { if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
// doesn't register if it's declared as a trait types.push(MethodType::new(t.clone(), vi.t.clone()));
if self.is_class(&types.first().unwrap().definition_type) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
}
self.method_to_types
.insert(class_method.inspect().clone(), types);
} else { } else {
self.method_to_types.insert( self.method_to_classes.insert(
class_method.inspect().clone(), class_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())], vec![MethodType::new(t.clone(), vi.t.clone())],
); );
@ -182,25 +177,20 @@ impl Context {
} }
} }
for (trait_method, vi) in ctx.decls.iter() { for (trait_method, vi) in ctx.decls.iter() {
if let Some(traits) = self.method_to_types.get_mut(trait_method.inspect()) { if let Some(traits) = self.method_to_traits.get_mut(trait_method.inspect()) {
traits.push(MethodType::new(t.clone(), vi.t.clone())); traits.push(MethodType::new(t.clone(), vi.t.clone()));
} else { } else {
self.method_to_types.insert( self.method_to_traits.insert(
trait_method.inspect().clone(), trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())], vec![MethodType::new(t.clone(), vi.t.clone())],
); );
} }
} }
for (class_method, vi) in ctx.locals.iter() { for (class_method, vi) in ctx.locals.iter() {
if let Some(mut types) = self.method_to_types.remove(class_method.inspect()) { if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
// doesn't register if it's declared as a trait types.push(MethodType::new(t.clone(), vi.t.clone()));
if self.is_class(&types.first().unwrap().definition_type) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
}
self.method_to_types
.insert(class_method.inspect().clone(), types);
} else { } else {
self.method_to_types.insert( self.method_to_classes.insert(
class_method.inspect().clone(), class_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())], vec![MethodType::new(t.clone(), vi.t.clone())],
); );

View file

@ -1764,16 +1764,17 @@ impl Context {
} }
fn get_method_type_by_name(&self, name: &Identifier) -> SingleTyCheckResult<&MethodType> { fn get_method_type_by_name(&self, name: &Identifier) -> SingleTyCheckResult<&MethodType> {
if let Some(candidates) = self.method_to_types.get(name.inspect()) { // TODO: min_by
if let Some(candidates) = self.method_to_traits.get(name.inspect()) {
let first_method_type = &candidates.first().unwrap().method_type; let first_method_type = &candidates.first().unwrap().method_type;
if candidates if candidates
.iter() .iter()
.skip(1) .skip(1)
.all(|t| &t.method_type == first_method_type) .all(|t| &t.method_type == first_method_type)
{ {
Ok(&candidates[0]) return Ok(&candidates[0]);
} else { } else {
Err(TyCheckError::ambiguous_type_error( return Err(TyCheckError::ambiguous_type_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
name, name,
@ -1782,9 +1783,31 @@ impl Context {
.map(|t| t.definition_type.clone()) .map(|t| t.definition_type.clone())
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
self.caused_by(), self.caused_by(),
)) ));
} }
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { }
if let Some(candidates) = self.method_to_classes.get(name.inspect()) {
let first_method_type = &candidates.first().unwrap().method_type;
if candidates
.iter()
.skip(1)
.all(|t| &t.method_type == first_method_type)
{
return Ok(&candidates[0]);
} else {
return Err(TyCheckError::ambiguous_type_error(
self.cfg.input.clone(),
line!() as usize,
name,
&candidates
.iter()
.map(|t| t.definition_type.clone())
.collect::<Vec<_>>(),
self.caused_by(),
));
}
}
if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
outer.get_method_type_by_name(name) outer.get_method_type_by_name(name)
} else { } else {
Err(TyCheckError::no_attr_error( Err(TyCheckError::no_attr_error(

View file

@ -347,7 +347,8 @@ pub struct Context {
pub(crate) methods_list: Vec<(ClassDefType, Context)>, pub(crate) methods_list: Vec<(ClassDefType, Context)>,
// K: method name, V: types defines the method // K: method name, V: types defines the method
// If it is declared in a trait, it takes precedence over the class. // If it is declared in a trait, it takes precedence over the class.
pub(crate) method_to_types: Dict<Str, Vec<MethodType>>, pub(crate) method_to_traits: Dict<Str, Vec<MethodType>>,
pub(crate) method_to_classes: Dict<Str, Vec<MethodType>>,
/// K: method name, V: impl patch /// K: method name, V: impl patch
/// Provided methods can switch implementations on a scope-by-scope basis /// Provided methods can switch implementations on a scope-by-scope basis
/// K: メソッド名, V: それを実装するパッチたち /// K: メソッド名, V: それを実装するパッチたち
@ -485,7 +486,8 @@ impl Context {
super_traits: vec![], super_traits: vec![],
methods_list: vec![], methods_list: vec![],
const_param_defaults: Dict::default(), const_param_defaults: Dict::default(),
method_to_types: Dict::default(), method_to_traits: Dict::default(),
method_to_classes: Dict::default(),
method_impl_patches: Dict::default(), method_impl_patches: Dict::default(),
trait_impls: Dict::default(), trait_impls: Dict::default(),
params: params_, params: params_,

View file

@ -848,25 +848,20 @@ impl Context {
} }
} }
for (trait_method, vi) in ctx.decls.iter() { for (trait_method, vi) in ctx.decls.iter() {
if let Some(types) = self.method_to_types.get_mut(trait_method.inspect()) { if let Some(types) = self.method_to_traits.get_mut(trait_method.inspect()) {
types.push(MethodType::new(t.clone(), vi.t.clone())); types.push(MethodType::new(t.clone(), vi.t.clone()));
} else { } else {
self.method_to_types.insert( self.method_to_traits.insert(
trait_method.inspect().clone(), trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())], vec![MethodType::new(t.clone(), vi.t.clone())],
); );
} }
} }
for (class_method, vi) in ctx.locals.iter() { for (class_method, vi) in ctx.locals.iter() {
if let Some(mut types) = self.method_to_types.remove(class_method.inspect()) { if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
// doesn't register if it's declared as a trait types.push(MethodType::new(t.clone(), vi.t.clone()));
if self.is_class(&types.first().unwrap().definition_type) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
}
self.method_to_types
.insert(class_method.inspect().clone(), types);
} else { } else {
self.method_to_types.insert( self.method_to_classes.insert(
class_method.inspect().clone(), class_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())], vec![MethodType::new(t.clone(), vi.t.clone())],
); );