Skip to content

Commit

Permalink
Fix various Chalk lowering bugs
Browse files Browse the repository at this point in the history
- Add more well-known traits
- Use the correct binders when lowering trait objects
- Use correct substs when lowering trait objects
- Use the correct binders for opaque_ty_data
- Lower negative impls with the correct polarity
- Supply associated type values
- Use `predicates_defined_on` for where clauses
  • Loading branch information
matthewjasper committed Oct 30, 2020
1 parent 299a65f commit acb6a06
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 42 deletions.
130 changes: 94 additions & 36 deletions compiler/rustc_traits/src/chalk/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<'tcx> RustIrDatabase<'tcx> {
def_id: DefId,
bound_vars: SubstsRef<'tcx>,
) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
let predicates = self.interner.tcx.predicates_of(def_id).predicates;
let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
let mut regions_substitutor =
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
predicates
Expand Down Expand Up @@ -118,34 +118,27 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
.map(|i| chalk_ir::AssocTypeId(i.def_id))
.collect();

let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) {
let lang_items = self.interner.tcx.lang_items();
let well_known = if lang_items.sized_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
} else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) {
} else if lang_items.copy_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
} else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) {
} else if lang_items.clone_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
} else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) {
} else if lang_items.drop_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
} else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) {
} else if lang_items.fn_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
} else if self
.interner
.tcx
.lang_items()
.fn_once_trait()
.map(|t| def_id == t)
.unwrap_or(false)
{
} else if lang_items.fn_once_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce)
} else if self
.interner
.tcx
.lang_items()
.fn_mut_trait()
.map(|t| def_id == t)
.unwrap_or(false)
{
} else if lang_items.fn_mut_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::FnMut)
} else if lang_items.unsize_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Unsize)
} else if lang_items.unpin_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Unpin)
} else if lang_items.coerce_unsized_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::CoerceUnsized)
} else {
None
};
Expand Down Expand Up @@ -281,11 +274,20 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
where_clauses,
};

let associated_ty_value_ids: Vec<_> = self
.interner
.tcx
.associated_items(def_id)
.in_definition_order()
.filter(|i| i.kind == AssocKind::Type)
.map(|i| chalk_solve::rust_ir::AssociatedTyValueId(i.def_id))
.collect();

Arc::new(chalk_solve::rust_ir::ImplDatum {
polarity: chalk_solve::rust_ir::Polarity::Positive,
polarity: self.interner.tcx.impl_polarity(def_id).lower_into(&self.interner),
binders: chalk_ir::Binders::new(binders, value),
impl_type: chalk_solve::rust_ir::ImplType::Local,
associated_ty_value_ids: vec![],
associated_ty_value_ids,
})
}

Expand Down Expand Up @@ -406,24 +408,38 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
let def_id = associated_ty_id.0;
let assoc_item = self.interner.tcx.associated_item(def_id);
let impl_id = match assoc_item.container {
AssocItemContainer::TraitContainer(def_id) => def_id,
_ => unimplemented!("Not possible??"),
let (impl_id, trait_id) = match assoc_item.container {
AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
AssocItemContainer::ImplContainer(def_id) => {
(def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
}
};
match assoc_item.kind {
AssocKind::Type => {}
_ => unimplemented!("Not possible??"),
}

let trait_item = self
.interner
.tcx
.associated_items(trait_id)
.find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
.unwrap();
let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
let binders = binders_for(&self.interner, bound_vars);
let ty = self.interner.tcx.type_of(def_id);
let ty = self
.interner
.tcx
.type_of(def_id)
.subst(self.interner.tcx, bound_vars)
.lower_into(&self.interner);

Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
impl_id: chalk_ir::ImplId(impl_id),
associated_ty_id: chalk_ir::AssocTypeId(def_id),
associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
value: chalk_ir::Binders::new(
binders,
chalk_solve::rust_ir::AssociatedTyValueBound { ty: ty.lower_into(&self.interner) },
chalk_solve::rust_ir::AssociatedTyValueBound { ty },
),
})
}
Expand All @@ -443,19 +459,61 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
&self,
opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
let bound_vars = bound_vars_for_item(self.interner.tcx, opaque_ty_id.0);
let binders = binders_for(&self.interner, bound_vars);
let bound_vars = ty::fold::shift_vars(
self.interner.tcx,
&bound_vars_for_item(self.interner.tcx, opaque_ty_id.0),
1,
);
let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars);
let bounds = self.bounds_for(opaque_ty_id.0, bound_vars);

let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0);

let bounds =
self.interner
.tcx
.explicit_item_bounds(opaque_ty_id.0)
.iter()
.map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
.map(|bound| {
bound.fold_with(&mut ty::fold::BottomUpFolder {
tcx: self.interner.tcx,
ty_op: |ty| {
if let ty::Opaque(def_id, substs) = *ty.kind() {
if def_id == opaque_ty_id.0 && substs == identity_substs {
return self.interner.tcx.mk_ty(ty::Bound(
ty::INNERMOST,
ty::BoundTy::from(ty::BoundVar::from_u32(0)),
));
}
}
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
})
.filter_map(|bound| {
LowerInto::<
Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
>::lower_into(bound, &self.interner)
})
.collect();

// Binder for the bound variable representing the concrete impl Trait type.
let existential_binder = chalk_ir::VariableKinds::from1(
&self.interner,
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
);

let value = chalk_solve::rust_ir::OpaqueTyDatumBound {
bounds: chalk_ir::Binders::new(binders.clone(), bounds),
where_clauses: chalk_ir::Binders::new(binders, where_clauses),
bounds: chalk_ir::Binders::new(existential_binder.clone(), bounds),
where_clauses: chalk_ir::Binders::new(existential_binder, where_clauses),
};

let binders = binders_for(&self.interner, bound_vars);
Arc::new(chalk_solve::rust_ir::OpaqueTyDatum {
opaque_ty_id,
bound: chalk_ir::Binders::empty(&self.interner, value),
bound: chalk_ir::Binders::new(binders, value),
})
}

Expand Down
40 changes: 34 additions & 6 deletions compiler/rustc_traits/src/chalk/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,16 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
self,
interner: &RustInterner<'tcx>,
) -> chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>> {
// `Self` has one binder:
// Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>
// The return type has two:
// Binders<&[Binders<WhereClause<I>>]>
// This means that any variables that are escaping `self` need to be
// shifted in by one so that they are still escaping.
let shifted_predicates = ty::fold::shift_vars(interner.tcx, &self, 1);

let (predicates, binders, _named_regions) =
collect_bound_vars(interner, interner.tcx, &self);
collect_bound_vars(interner, interner.tcx, &shifted_predicates);
let self_ty = interner.tcx.mk_ty(ty::Bound(
// This is going to be wrapped in a binder
ty::DebruijnIndex::from_usize(1),
Expand All @@ -648,7 +656,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
let where_clauses = predicates.into_iter().map(|predicate| match predicate {
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => {
chalk_ir::Binders::new(
chalk_ir::VariableKinds::empty(interner),
binders.clone(),
chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
trait_id: chalk_ir::TraitId(def_id),
substitution: interner
Expand All @@ -659,25 +667,34 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
)
}
ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new(
chalk_ir::VariableKinds::empty(interner),
binders.clone(),
chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq {
alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id),
substitution: predicate.substs.lower_into(interner),
substitution: interner
.tcx
.mk_substs_trait(self_ty, predicate.substs)
.lower_into(interner),
}),
ty: predicate.ty.lower_into(interner),
}),
),
ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
chalk_ir::VariableKinds::empty(interner),
binders.clone(),
chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
trait_id: chalk_ir::TraitId(def_id),
substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner),
}),
),
});

// Binder for the bound variable representing the concrete underlying type.
let existential_binder = chalk_ir::VariableKinds::from1(
interner,
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
);
let value = chalk_ir::QuantifiedWhereClauses::from_iter(interner, where_clauses);
chalk_ir::Binders::new(binders, value)
chalk_ir::Binders::new(existential_binder, value)
}
}

Expand Down Expand Up @@ -750,6 +767,17 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>>>
}
}

impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::Polarity> for ty::ImplPolarity {
fn lower_into(self, _interner: &RustInterner<'tcx>) -> chalk_solve::rust_ir::Polarity {
match self {
ty::ImplPolarity::Positive => chalk_solve::rust_ir::Polarity::Positive,
ty::ImplPolarity::Negative => chalk_solve::rust_ir::Polarity::Negative,
// FIXME(chalk) reservation impls
ty::ImplPolarity::Reservation => chalk_solve::rust_ir::Polarity::Negative,
}
}
}

impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
for ty::ProjectionPredicate<'tcx>
{
Expand Down
20 changes: 20 additions & 0 deletions src/test/ui/chalkify/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// check-pass
// compile-flags: -Z chalk

fn main() {
1 + 2;
3 * 6;
2 - 5;
17 / 6;
23 % 11;
4 & 6;
7 | 15;
4 << 7;
123 >> 3;
1 == 2;
5 != 5;
6 < 2;
7 > 11;
3 <= 1;
9 >= 14;
}
13 changes: 13 additions & 0 deletions src/test/ui/chalkify/trait-objects.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// check-pass
// compile-flags: -Z chalk

use std::fmt::Display;

fn main() {
let d: &dyn Display = &mut 3;
// FIXME(chalk) should be able to call d.to_string() as well, but doing so
// requires Chalk to be able to prove trait object well-formed goals.
(&d).to_string();
let f: &dyn Fn(i32) -> _ = &|x| x + x;
f(2);
}

0 comments on commit acb6a06

Please sign in to comment.