Skip to content

Commit

Permalink
frontend: Get trait-default-collect.dora to work
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Feb 13, 2025
1 parent a3e6630 commit 54deed4
Show file tree
Hide file tree
Showing 10 changed files with 335 additions and 52 deletions.
57 changes: 43 additions & 14 deletions dora-frontend/src/parsety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1103,28 +1103,42 @@ pub fn expand_type(
new_ty
}

pub fn expand_trait_type(
pub fn expand_parsed_trait_type(
sa: &Sema,
element: &dyn Element,
parsed_ty: &ParsedTraitType,
replace_self: Option<SourceType>,
) {
if let Some(trait_ty) = parsed_ty.ty() {
let new_type_params = expand_sta(sa, element, &trait_ty.type_params, replace_self.clone());
let new_bindings = trait_ty
.bindings
.into_iter()
.map(|(id, ty)| (id, expand_st(sa, element, ty, replace_self.clone())))
.collect();
let new_trait_ty = TraitType {
trait_id: trait_ty.trait_id,
type_params: new_type_params,
bindings: new_bindings,
};
let new_trait_ty = expand_trait_ty(sa, element, &trait_ty, replace_self);
parsed_ty.set_ty(Some(new_trait_ty));
}
}

fn expand_trait_ty(
sa: &Sema,
element: &dyn Element,
trait_ty: &TraitType,
replace_self: Option<SourceType>,
) -> TraitType {
let new_type_params = expand_sta(sa, element, &trait_ty.type_params, replace_self.clone());
let new_bindings = trait_ty
.bindings
.iter()
.map(|(id, ty)| {
(
*id,
expand_st(sa, element, ty.clone(), replace_self.clone()),
)
})
.collect::<Vec<_>>();
TraitType {
trait_id: trait_ty.trait_id,
type_params: new_type_params,
bindings: new_bindings,
}
}

fn expand_st(
sa: &Sema,
element: &dyn Element,
Expand Down Expand Up @@ -1195,6 +1209,22 @@ fn expand_st(
}
}

SourceType::GenericAssoc {
tp_id,
trait_ty,
assoc_id,
} => {
if let Some((_, ty)) = trait_ty.bindings.iter().find(|(x, _)| *x == *assoc_id) {
expand_st(sa, element, ty.clone(), replace_self)
} else {
SourceType::GenericAssoc {
tp_id: *tp_id,
trait_ty: expand_trait_ty(sa, element, trait_ty, replace_self),
assoc_id: *assoc_id,
}
}
}

SourceType::Unit
| SourceType::UInt8
| SourceType::Bool
Expand All @@ -1204,8 +1234,7 @@ fn expand_st(
| SourceType::Float32
| SourceType::Float64
| SourceType::Error
| SourceType::TypeParam(..)
| SourceType::GenericAssoc { .. } => ty,
| SourceType::TypeParam(..) => ty,
SourceType::This => replace_self.expect("self expected"),

SourceType::Any | SourceType::Ptr => {
Expand Down
142 changes: 122 additions & 20 deletions dora-frontend/src/specialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,7 @@ use crate::sema::{
use crate::{SourceType, SourceTypeArray, TraitType};

pub fn specialize_trait_type(sa: &Sema, ty: TraitType, type_params: &SourceTypeArray) -> TraitType {
TraitType {
trait_id: ty.trait_id,
type_params: replace_sta(sa, ty.type_params, Some(type_params), None),
bindings: ty
.bindings
.into_iter()
.map(|(id, ty)| (id, replace_type(sa, ty, Some(type_params), None)))
.collect(),
}
specialize_trait_type_generic(sa, ty, &|ty| replace_type(sa, ty, Some(type_params), None))
}

pub fn specialize_trait_type_generic<S>(_sa: &Sema, ty: TraitType, specialize: &S) -> TraitType
Expand All @@ -26,14 +18,19 @@ where
.map(|ty| specialize(ty))
.collect::<Vec<_>>();

let mut new_bindings = Vec::with_capacity(ty.bindings.len());

for (id, ty) in ty.bindings {
let ty = specialize(ty);
if SourceType::Assoc(id, SourceTypeArray::empty()) != ty {
new_bindings.push((id, ty));
}
}

TraitType {
trait_id: ty.trait_id,
type_params: type_params.into(),
bindings: ty
.bindings
.into_iter()
.map(|(id, ty)| (id, specialize(ty)))
.collect(),
bindings: new_bindings,
}
}

Expand Down Expand Up @@ -502,7 +499,53 @@ pub fn specialize_ty_for_default_trait_method(
}
}

SourceType::GenericAssoc { .. } => unimplemented!(),
SourceType::GenericAssoc {
tp_id,
trait_ty: local_trait_ty,
assoc_id,
} => {
let assoc = sa.alias(assoc_id);
assert!(assoc.parent.is_trait());
let type_param_ty = specialize_ty_for_default_trait_method(
sa,
SourceType::TypeParam(tp_id),
trait_method,
impl_,
trait_ty,
extended_ty,
);

if type_param_ty.is_type_param() {
SourceType::GenericAssoc {
tp_id: type_param_ty.type_param_id().expect("missing"),
trait_ty: local_trait_ty,
assoc_id,
}
} else if let Some(impl_match) = find_impl(
sa,
trait_method,
type_param_ty,
trait_method.type_param_definition(),
local_trait_ty.clone(),
) {
let impl_ = sa.impl_(impl_match.id);
let ty = impl_
.trait_alias_map()
.get(&assoc_id)
.map(|a| sa.alias(*a).ty())
.unwrap_or(SourceType::Error);
specialize_ty_for_default_trait_method(
sa,
ty,
trait_method,
impl_,
trait_ty,
extended_ty,
)
} else {
unimplemented!()
}
}

SourceType::Lambda(params, return_type) => SourceType::Lambda(
specialize_ty_array_for_default_trait_method(
Expand Down Expand Up @@ -596,6 +639,7 @@ fn specialize_ty_array_for_default_trait_method(
pub fn specialize_ty_for_generic(
sa: &Sema,
ty: SourceType,
element: &dyn Element,
type_param_id: TypeParamId,
trait_ty: &TraitType,
type_params: &SourceTypeArray,
Expand All @@ -607,6 +651,7 @@ pub fn specialize_ty_for_generic(
specialize_ty_for_generic_array(
sa,
cls_type_params,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -619,6 +664,7 @@ pub fn specialize_ty_for_generic(
specialize_ty_for_generic_array(
sa,
trait_type_params,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -627,6 +673,7 @@ pub fn specialize_ty_for_generic(
specialize_ty_for_generic_array(
sa,
bindings,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -639,6 +686,7 @@ pub fn specialize_ty_for_generic(
specialize_ty_for_generic_array(
sa,
struct_type_params,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -651,6 +699,7 @@ pub fn specialize_ty_for_generic(
specialize_ty_for_generic_array(
sa,
enum_type_params,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -663,6 +712,7 @@ pub fn specialize_ty_for_generic(
specialize_ty_for_generic_array(
sa,
alias_type_params,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -674,17 +724,65 @@ pub fn specialize_ty_for_generic(
let alias = sa.alias(alias_id);
assert_eq!(alias.parent, AliasParent::Trait(trait_ty.trait_id));
assert!(alias_type_params.is_empty());
SourceType::GenericAssoc {
tp_id: type_param_id,
trait_ty: trait_ty.clone(),
assoc_id: alias_id,

if let Some((_, ty)) = trait_ty.bindings.iter().find(|(x, _)| *x == alias_id) {
ty.clone()
} else {
SourceType::GenericAssoc {
tp_id: type_param_id,
trait_ty: trait_ty.clone(),
assoc_id: alias_id,
}
}
}

SourceType::GenericAssoc {
tp_id,
trait_ty: local_trait_ty,
assoc_id,
} => {
let assoc = sa.alias(assoc_id);
assert!(assoc.parent.is_trait());
let type_param_ty = type_params[tp_id.index()].clone();

if type_param_ty.is_type_param() {
SourceType::GenericAssoc {
tp_id: type_param_ty.type_param_id().expect("missing"),
trait_ty: local_trait_ty,
assoc_id,
}
} else if let Some(impl_match) = find_impl(
sa,
element,
type_param_ty,
element.type_param_definition(),
local_trait_ty.clone(),
) {
let impl_ = sa.impl_(impl_match.id);
let ty = impl_
.trait_alias_map()
.get(&assoc_id)
.map(|a| sa.alias(*a).ty())
.unwrap_or(SourceType::Error);
specialize_ty_for_generic(
sa,
ty,
element,
type_param_id,
trait_ty,
type_params,
object_type,
)
} else {
unimplemented!()
}
}

SourceType::Lambda(params, return_type) => SourceType::Lambda(
specialize_ty_for_generic_array(
sa,
params,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -693,6 +791,7 @@ pub fn specialize_ty_for_generic(
Box::new(specialize_ty_for_generic(
sa,
*return_type,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -703,6 +802,7 @@ pub fn specialize_ty_for_generic(
SourceType::Tuple(subtypes) => SourceType::Tuple(specialize_ty_for_generic_array(
sa,
subtypes,
element,
type_param_id,
trait_ty,
type_params,
Expand All @@ -723,7 +823,7 @@ pub fn specialize_ty_for_generic(

SourceType::This => object_type.clone(),

SourceType::Any | SourceType::Ptr | SourceType::GenericAssoc { .. } => {
SourceType::Any | SourceType::Ptr => {
unreachable!()
}
}
Expand All @@ -732,6 +832,7 @@ pub fn specialize_ty_for_generic(
fn specialize_ty_for_generic_array(
sa: &Sema,
array: SourceTypeArray,
element: &dyn Element,
type_param_id: TypeParamId,
trait_ty: &TraitType,
trait_type_params: &SourceTypeArray,
Expand All @@ -743,6 +844,7 @@ fn specialize_ty_for_generic_array(
specialize_ty_for_generic(
sa,
ty,
element,
type_param_id,
trait_ty,
trait_type_params,
Expand Down
28 changes: 28 additions & 0 deletions dora-frontend/src/traitdefck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,4 +582,32 @@ mod tests {
class Foo[T: TraitA](T)
");
}

#[test]
fn trait_default_method_returning_known_associated_type() {
ok("
trait Foo {
fn bar[T: Bar[X=String]](x: T): T::X { x.toX() }
}
trait Bar {
type X;
fn toX(): Self::X;
}
");
}

#[test]
fn trait_default_method_returning_known_associated_type_fixed() {
ok("
trait Foo {
fn bar[T: Bar[X=String]](x: T): String { x.toX() }
}
trait Bar {
type X;
fn toX(): Self::X;
}
");
}
}
Loading

0 comments on commit 54deed4

Please sign in to comment.