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() {
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()));
} else {
self.method_to_types.insert(
self.method_to_traits.insert(
trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
}
}
for (class_method, vi) in ctx.locals.iter() {
if let Some(mut types) = self.method_to_types.remove(class_method.inspect()) {
// doesn't register if it's declared as a trait
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);
if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
} else {
self.method_to_types.insert(
self.method_to_classes.insert(
class_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
@ -182,25 +177,20 @@ impl Context {
}
}
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()));
} else {
self.method_to_types.insert(
self.method_to_traits.insert(
trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
}
}
for (class_method, vi) in ctx.locals.iter() {
if let Some(mut types) = self.method_to_types.remove(class_method.inspect()) {
// doesn't register if it's declared as a trait
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);
if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
} else {
self.method_to_types.insert(
self.method_to_classes.insert(
class_method.inspect().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> {
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;
if candidates
.iter()
.skip(1)
.all(|t| &t.method_type == first_method_type)
{
Ok(&candidates[0])
return Ok(&candidates[0]);
} else {
Err(TyCheckError::ambiguous_type_error(
return Err(TyCheckError::ambiguous_type_error(
self.cfg.input.clone(),
line!() as usize,
name,
@ -1782,9 +1783,31 @@ impl Context {
.map(|t| t.definition_type.clone())
.collect::<Vec<_>>(),
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)
} else {
Err(TyCheckError::no_attr_error(

View file

@ -347,7 +347,8 @@ pub struct Context {
pub(crate) methods_list: Vec<(ClassDefType, Context)>,
// K: method name, V: types defines the method
// 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
/// Provided methods can switch implementations on a scope-by-scope basis
/// K: メソッド名, V: それを実装するパッチたち
@ -485,7 +486,8 @@ impl Context {
super_traits: vec![],
methods_list: vec![],
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(),
trait_impls: Dict::default(),
params: params_,

View file

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