Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
-rw-r--r--crates/hir-ty/src/lower.rs105
1 files changed, 67 insertions, 38 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 895c2e7846..1289f9a73a 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1680,10 +1680,16 @@ impl SupertraitsInfo {
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-enum TypeParamAssocTypeShorthandError {
- AssocTypeNotFound,
- AmbiguousAssocType,
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+enum AssocTypeShorthandResolution {
+ Resolved(StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>),
+ Ambiguous {
+ /// If one resolution belongs to a sub-trait and one to a supertrait, this contains
+ /// the sub-trait's resolution. This can be `None` if there is no trait inheritance
+ /// relationship between the resolutions.
+ sub_trait_resolution: Option<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>>,
+ },
+ NotFound,
Cycle,
}
@@ -1707,7 +1713,7 @@ fn resolve_type_param_assoc_type_shorthand(
def: GenericDefId,
param: TypeParamId,
assoc_name: Name,
-) -> Result<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>, TypeParamAssocTypeShorthandError> {
+) -> AssocTypeShorthandResolution {
let generics = generics(db, def);
let resolver = def.resolver(db);
let mut ctx = TyLoweringContext::new(
@@ -1718,13 +1724,13 @@ fn resolve_type_param_assoc_type_shorthand(
LifetimeElisionKind::AnonymousReportError,
);
let interner = ctx.interner;
- let mut result = None;
let param_ty = Ty::new_param(
interner,
param,
generics.type_or_const_param_idx(param.into()).unwrap() as u32,
);
+ let mut this_trait_resolution = None;
if let GenericDefId::TraitId(containing_trait) = param.parent()
&& param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF
{
@@ -1733,10 +1739,11 @@ fn resolve_type_param_assoc_type_shorthand(
containing_trait.trait_items(db).associated_type_by_name(&assoc_name)
{
let args = GenericArgs::identity_for_item(interner, containing_trait.into());
- result = Some(StoredEarlyBinder::bind((assoc_type, args.store())));
+ this_trait_resolution = Some(StoredEarlyBinder::bind((assoc_type, args.store())));
}
}
+ let mut supertraits_resolution = None;
for maybe_parent_generics in
std::iter::successors(Some(&generics), |generics| generics.parent_generics())
{
@@ -1782,34 +1789,53 @@ fn resolve_type_param_assoc_type_shorthand(
TypeParamId::trait_self(bounded_trait),
assoc_name.clone(),
);
- let lookup_on_bounded_trait = match lookup_on_bounded_trait {
- Ok(it) => it,
- Err(
- err @ (TypeParamAssocTypeShorthandError::AmbiguousAssocType
- | TypeParamAssocTypeShorthandError::Cycle),
- ) => return Err(*err),
- Err(TypeParamAssocTypeShorthandError::AssocTypeNotFound) => {
+ let assoc_type_and_args = match &lookup_on_bounded_trait {
+ AssocTypeShorthandResolution::Resolved(trait_ref) => trait_ref,
+ AssocTypeShorthandResolution::Ambiguous {
+ sub_trait_resolution: Some(trait_ref),
+ } => trait_ref,
+ AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None } => {
+ return AssocTypeShorthandResolution::Ambiguous {
+ sub_trait_resolution: this_trait_resolution,
+ };
+ }
+ AssocTypeShorthandResolution::NotFound => {
never!("we checked that the trait defines this assoc type");
continue;
}
+ AssocTypeShorthandResolution::Cycle => return AssocTypeShorthandResolution::Cycle,
};
- let (assoc_type, args) = lookup_on_bounded_trait
- .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref()))
- .skip_binder();
- let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args);
- let current_result = StoredEarlyBinder::bind((assoc_type, args.store()));
- // If we already have a result, this is an ambiguity - unless this is the same result, then we are fine
- // (e.g. rustc allows to write the same bound twice without ambiguity).
- if let Some(existing_result) = result
- && existing_result != current_result
- {
- return Err(TypeParamAssocTypeShorthandError::AmbiguousAssocType);
+ if let Some(this_trait_resolution) = this_trait_resolution {
+ return AssocTypeShorthandResolution::Ambiguous {
+ sub_trait_resolution: Some(this_trait_resolution),
+ };
+ } else if supertraits_resolution.is_some() {
+ return AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None };
+ } else {
+ let (assoc_type, args) = assoc_type_and_args
+ .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref()))
+ .skip_binder();
+ let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args);
+ let current_result = StoredEarlyBinder::bind((assoc_type, args.store()));
+ supertraits_resolution = Some(match lookup_on_bounded_trait {
+ AssocTypeShorthandResolution::Resolved(_) => {
+ AssocTypeShorthandResolution::Resolved(current_result)
+ }
+ AssocTypeShorthandResolution::Ambiguous { .. } => {
+ AssocTypeShorthandResolution::Ambiguous {
+ sub_trait_resolution: Some(current_result),
+ }
+ }
+ AssocTypeShorthandResolution::NotFound
+ | AssocTypeShorthandResolution::Cycle => unreachable!(),
+ });
}
- result = Some(current_result);
}
}
- result.ok_or(TypeParamAssocTypeShorthandError::AssocTypeNotFound)
+ supertraits_resolution
+ .or_else(|| this_trait_resolution.map(AssocTypeShorthandResolution::Resolved))
+ .unwrap_or(AssocTypeShorthandResolution::NotFound)
}
fn resolve_type_param_assoc_type_shorthand_cycle_result(
@@ -1818,8 +1844,8 @@ fn resolve_type_param_assoc_type_shorthand_cycle_result(
_def: GenericDefId,
_param: TypeParamId,
_assoc_name: Name,
-) -> Result<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>, TypeParamAssocTypeShorthandError> {
- Err(TypeParamAssocTypeShorthandError::Cycle)
+) -> AssocTypeShorthandResolution {
+ AssocTypeShorthandResolution::Cycle
}
#[inline]
@@ -2568,19 +2594,22 @@ pub(crate) fn associated_ty_item_bounds<'db>(
EarlyBinder::bind(BoundExistentialPredicates::new_from_slice(&bounds))
}
-pub(crate) fn associated_type_by_name_including_super_traits<'db>(
+pub(crate) fn associated_type_by_name_including_super_traits_allow_ambiguity<'db>(
db: &'db dyn HirDatabase,
trait_ref: TraitRef<'db>,
name: Name,
) -> Option<(TypeAliasId, GenericArgs<'db>)> {
- let assoc_type = resolve_type_param_assoc_type_shorthand(
- db,
- trait_ref.def_id.0.into(),
- TypeParamId::trait_self(trait_ref.def_id.0),
- name.clone(),
- )
- .as_ref()
- .ok()?;
+ let (AssocTypeShorthandResolution::Resolved(assoc_type)
+ | AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: Some(assoc_type) }) =
+ resolve_type_param_assoc_type_shorthand(
+ db,
+ trait_ref.def_id.0.into(),
+ TypeParamId::trait_self(trait_ref.def_id.0),
+ name.clone(),
+ )
+ else {
+ return None;
+ };
let (assoc_type, trait_args) = assoc_type
.get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
.skip_binder();