Skip to content

Commit

Permalink
Add Outlives bounds to GenericPredicate
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Feb 20, 2021
1 parent ba3a5c5 commit b9d6904
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 42 deletions.
4 changes: 4 additions & 0 deletions crates/hir_def/src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,10 @@ impl GenericParams {
self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None })
}

pub fn find_lifetime_by_name(&self, name: &Name) -> Option<LocalLifetimeParamId> {
self.lifetimes.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None })
}

pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
self.types.iter().find_map(|(id, p)| {
if p.provenance == TypeParamProvenance::TraitSelf {
Expand Down
20 changes: 20 additions & 0 deletions crates/hir_def/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
nameres::DefMap,
path::{ModPath, PathKind},
per_ns::PerNs,
type_ref::LifetimeRef,
visibility::{RawVisibility, Visibility},
AdtId, AssocContainerId, ConstId, ConstParamId, ContainerId, DefWithBodyId, EnumId,
EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId,
Expand Down Expand Up @@ -199,6 +200,25 @@ impl Resolver {
None
}

pub fn resolve_lifetime(
&self,
_db: &dyn DefDatabase,
lifetime: &LifetimeRef,
) -> Option<LifetimeParamId> {
self.scopes
.iter()
.rev()
.find_map(|scope| match scope {
Scope::GenericParams { params, def } => Some((params, def)),
_ => None,
})
.and_then(|(params, def)| {
params
.find_lifetime_by_name(&lifetime.name)
.map(|local_id| LifetimeParamId { local_id, parent: *def })
})
}

pub fn resolve_path_in_type_ns_fully(
&self,
db: &dyn DefDatabase,
Expand Down
1 change: 1 addition & 0 deletions crates/hir_expand/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ pub mod known {
pub const SELF_TYPE: super::Name = super::Name::new_inline("Self");

pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static");
pub const PLACEHOLDER_LIFETIME: super::Name = super::Name::new_inline("'_");

#[macro_export]
macro_rules! name {
Expand Down
12 changes: 12 additions & 0 deletions crates/hir_ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,8 @@ pub fn write_bounds_like_dyn_trait(
write!(f, "{} = ", type_alias.name)?;
projection_pred.ty.hir_fmt(f)?;
}
GenericPredicate::LifetimeOutlives(outlives) => outlives.b.hir_fmt(f)?,
GenericPredicate::TypeOutlives(outlives) => outlives.lifetime.hir_fmt(f)?,
GenericPredicate::Error => {
if angle_open {
// impl Trait<X, {error}>
Expand Down Expand Up @@ -762,6 +764,16 @@ impl HirDisplay for GenericPredicate {
)?;
projection_pred.ty.hir_fmt(f)?;
}
GenericPredicate::LifetimeOutlives(outlives) => {
outlives.a.hir_fmt(f)?;
write!(f, ": ")?;
outlives.b.hir_fmt(f)?;
}
GenericPredicate::TypeOutlives(ty_outlives) => {
ty_outlives.ty.hir_fmt(f)?;
write!(f, ": ")?;
ty_outlives.lifetime.hir_fmt(f)?;
}
GenericPredicate::Error => write!(f, "{{error}}")?,
}
Ok(())
Expand Down
13 changes: 11 additions & 2 deletions crates/hir_ty/src/infer/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,17 @@ impl InferenceTable {

(Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true,

(Ty::Dyn(dyn1), Ty::Dyn(dyn2)) if dyn1.len() == dyn2.len() => {
for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) {
(Ty::Dyn(dyn1), Ty::Dyn(dyn2)) => {
// FIXME we dont properly handle lifetimes yet so for now ignore theses predicates
let filter = |pred: &&_| {
!matches!(
pred,
GenericPredicate::LifetimeOutlives(_) | GenericPredicate::TypeOutlives(_)
)
};
for (pred1, pred2) in
dyn1.iter().take_while(filter).zip(dyn2.iter().take_while(filter))
{
if !self.unify_preds(pred1, pred2, depth + 1) {
return false;
}
Expand Down
26 changes: 23 additions & 3 deletions crates/hir_ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,18 @@ impl TypeWalk for TraitRef {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct LifetimeOutlives {
pub a: Lifetime,
pub b: Lifetime,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TypeOutlives {
pub ty: Ty,
pub lifetime: Lifetime,
}

/// Like `generics::WherePredicate`, but with resolved types: A condition on the
/// parameters of a generic item.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand All @@ -600,6 +612,8 @@ pub enum GenericPredicate {
Implemented(TraitRef),
/// An associated type bindings like in `Iterator<Item = T>`.
Projection(ProjectionPredicate),
LifetimeOutlives(LifetimeOutlives),
TypeOutlives(TypeOutlives),
/// We couldn't resolve the trait reference. (If some type parameters can't
/// be resolved, they will just be Unknown).
Error,
Expand All @@ -618,7 +632,9 @@ impl GenericPredicate {
match self {
GenericPredicate::Implemented(tr) => Some(tr.clone()),
GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)),
GenericPredicate::Error => None,
GenericPredicate::TypeOutlives(_)
| GenericPredicate::LifetimeOutlives(_)
| GenericPredicate::Error => None,
}
}
}
Expand All @@ -628,7 +644,9 @@ impl TypeWalk for GenericPredicate {
match self {
GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
GenericPredicate::Projection(projection_pred) => projection_pred.walk(f),
GenericPredicate::Error => {}
GenericPredicate::TypeOutlives(_)
| GenericPredicate::LifetimeOutlives(_)
| GenericPredicate::Error => {}
}
}

Expand All @@ -642,7 +660,9 @@ impl TypeWalk for GenericPredicate {
GenericPredicate::Projection(projection_pred) => {
projection_pred.walk_mut_binders(f, binders)
}
GenericPredicate::Error => {}
GenericPredicate::TypeOutlives(_)
| GenericPredicate::LifetimeOutlives(_)
| GenericPredicate::Error => {}
}
}
}
Expand Down
62 changes: 41 additions & 21 deletions crates/hir_ty/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ use hir_def::{
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
path::{GenericArg, Path, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{TypeBound, TypeRef},
type_ref::{LifetimeRef, TypeBound, TypeRef},
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
TypeAliasId, TypeParamId, UnionId, VariantId,
};
use hir_expand::name::Name;
use hir_expand::name::{known, Name};
use la_arena::ArenaMap;
use smallvec::SmallVec;
use stdx::impl_from;
Expand All @@ -31,9 +31,9 @@ use crate::{
all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
make_mut_slice, variant_data,
},
Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig,
ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs,
TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, Lifetime, LifetimeOutlives,
OpaqueTy, OpaqueTyId, PolyFnSig, ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait,
ReturnTypeImplTraits, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeOutlives, TypeWalk,
};

#[derive(Debug)]
Expand Down Expand Up @@ -655,15 +655,16 @@ impl TraitRef {
) -> Substs {
substs_from_path_segment(ctx, segment, Some(resolved.into()), false)
}
}

pub(crate) fn from_type_bound(
ctx: &TyLoweringContext<'_>,
bound: &TypeBound,
self_ty: Ty,
) -> Option<TraitRef> {
match bound {
TypeBound::Path(path) => TraitRef::from_path(ctx, path, Some(self_ty)),
TypeBound::Lifetime(_) | TypeBound::Error => None,
impl Lifetime {
fn from_lifetime_ref(ctx: &TyLoweringContext<'_>, lifetime_ref: &LifetimeRef) -> Option<Self> {
if lifetime_ref.name == known::STATIC_LIFETIME {
Some(Lifetime::Static)
} else if lifetime_ref.name == known::PLACEHOLDER_LIFETIME {
Some(Lifetime::Static)
} else {
ctx.resolver.resolve_lifetime(ctx.db.upcast(), lifetime_ref).map(Lifetime::Parameter)
}
}
}
Expand Down Expand Up @@ -696,7 +697,15 @@ impl GenericPredicate {
.collect::<Vec<_>>()
.into_iter()
}
WherePredicate::Lifetime { .. } => vec![].into_iter(),
WherePredicate::Lifetime { target, bound } => {
let a = Lifetime::from_lifetime_ref(ctx, target);
let b = Lifetime::from_lifetime_ref(ctx, bound);
a.zip(b)
.map(|(a, b)| GenericPredicate::LifetimeOutlives(LifetimeOutlives { a, b }))
.into_iter()
.collect::<Vec<_>>()
.into_iter()
}
}
}

Expand All @@ -705,13 +714,24 @@ impl GenericPredicate {
bound: &'a TypeBound,
self_ty: Ty,
) -> impl Iterator<Item = GenericPredicate> + 'a {
let trait_ref = TraitRef::from_type_bound(ctx, bound, self_ty);
iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented))
.chain(
trait_ref
.into_iter()
.flat_map(move |tr| assoc_type_bindings_from_type_bound(ctx, bound, tr)),
)
let mut bindings = None;
let trait_ref = match bound {
TypeBound::Path(path) => {
bindings = TraitRef::from_path(ctx, path, Some(self_ty));
bindings.clone().map(GenericPredicate::Implemented)
}
TypeBound::Lifetime(lifetime) => {
Lifetime::from_lifetime_ref(ctx, lifetime).map(|lifetime| {
GenericPredicate::TypeOutlives(TypeOutlives { lifetime, ty: self_ty })
})
}
TypeBound::Error => None,
};
iter::once(trait_ref.unwrap_or(GenericPredicate::Error)).chain(
bindings
.into_iter()
.flat_map(move |tr| assoc_type_bindings_from_type_bound(ctx, bound, tr)),
)
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/hir_ty/src/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ pub(crate) fn inherent_impl_substs(
// Unknown. I think this can only really happen if self_ty contained
// Unknown, and in that case we want the result to contain Unknown in those
// places again.

substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len()))
}

Expand Down
4 changes: 2 additions & 2 deletions crates/hir_ty/src/tests/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,14 +1114,14 @@ fn method_on_dyn_impl() {
trait Foo {}
impl Foo for u32 {}
impl dyn Foo {
impl dyn Foo + '_ {
pub fn dyn_foo(&self) -> u32 {
0
}
}
fn main() {
let f = &42u32 as &dyn Foo<u32>;
let f = &42u32 as &dyn Foo;
f.dyn_foo();
// ^u32
}
Expand Down
2 changes: 2 additions & 0 deletions crates/hir_ty/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ impl Obligation {
GenericPredicate::Projection(projection_pred) => {
Some(Obligation::Projection(projection_pred))
}
GenericPredicate::LifetimeOutlives(_) => None,
GenericPredicate::TypeOutlives(_) => None,
GenericPredicate::Error => None,
}
}
Expand Down
53 changes: 42 additions & 11 deletions crates/hir_ty/src/traits/chalk/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ use crate::{
db::HirDatabase,
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
traits::{Canonical, Obligation},
ApplicationTy, CallableDefId, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
ApplicationTy, CallableDefId, GenericPredicate, InEnvironment, Lifetime, LifetimeOutlives,
OpaqueTy, OpaqueTyId, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef,
Ty, TyKind, TypeCtor, TypeOutlives,
};

use super::interner::*;
Expand Down Expand Up @@ -268,6 +269,16 @@ impl ToChalk for Ty {
}
}

impl ToChalk for Lifetime {
type Chalk = chalk_ir::Lifetime<Interner>;
fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_ir::Lifetime<Interner> {
LifetimeData::Static.intern(&Interner) // FIXME
}
fn from_chalk(_db: &dyn HirDatabase, _chalk: chalk_ir::Lifetime<Interner>) -> Self {
Lifetime::Static // FIXME
}
}

fn apply_ty_from_chalk(
db: &dyn HirDatabase,
ctor: TypeCtor,
Expand Down Expand Up @@ -526,6 +537,22 @@ impl ToChalk for GenericPredicate {
let alias = chalk_ir::AliasTy::Projection(projection);
make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
}
GenericPredicate::LifetimeOutlives(outlives) => {
let a = outlives.a.to_chalk(db).shifted_in(&Interner);
let b = outlives.b.to_chalk(db).shifted_in(&Interner);
make_binders(
chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a, b }),
0,
)
}
GenericPredicate::TypeOutlives(outlives) => {
let ty = outlives.ty.to_chalk(db).shifted_in(&Interner);
let lifetime = outlives.lifetime.to_chalk(db).shifted_in(&Interner);
make_binders(
chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { ty, lifetime }),
0,
)
}
GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
}
}
Expand Down Expand Up @@ -555,15 +582,17 @@ impl ToChalk for GenericPredicate {
let ty = from_chalk(db, projection_eq.ty);
GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty })
}

chalk_ir::WhereClause::LifetimeOutlives(_) => {
// we shouldn't get these from Chalk
panic!("encountered LifetimeOutlives from Chalk")
chalk_ir::WhereClause::LifetimeOutlives(outlives) => {
GenericPredicate::LifetimeOutlives(LifetimeOutlives {
a: from_chalk(db, outlives.a),
b: from_chalk(db, outlives.b),
})
}

chalk_ir::WhereClause::TypeOutlives(_) => {
// we shouldn't get these from Chalk
panic!("encountered TypeOutlives from Chalk")
chalk_ir::WhereClause::TypeOutlives(outlives) => {
GenericPredicate::TypeOutlives(TypeOutlives {
ty: from_chalk(db, outlives.ty),
lifetime: from_chalk(db, outlives.lifetime),
})
}
}
}
Expand Down Expand Up @@ -799,6 +828,8 @@ pub(super) fn generic_predicate_to_inline_bound(
};
Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound))
}
GenericPredicate::Error => None,
GenericPredicate::LifetimeOutlives(_)
| GenericPredicate::TypeOutlives(_)
| GenericPredicate::Error => None,
}
}
Loading

0 comments on commit b9d6904

Please sign in to comment.