From acb6a061237053971bc75ca6477b39a8cbf13822 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 28 Oct 2020 20:04:39 +0000 Subject: [PATCH] Fix various Chalk lowering bugs - 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 --- compiler/rustc_traits/src/chalk/db.rs | 130 ++++++++++++++------ compiler/rustc_traits/src/chalk/lowering.rs | 40 +++++- src/test/ui/chalkify/arithmetic.rs | 20 +++ src/test/ui/chalkify/trait-objects.rs | 13 ++ 4 files changed, 161 insertions(+), 42 deletions(-) create mode 100644 src/test/ui/chalkify/arithmetic.rs create mode 100644 src/test/ui/chalkify/trait-objects.rs diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index eba1a525cfeb0..c5a46b1003dfa 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -37,7 +37,7 @@ impl<'tcx> RustIrDatabase<'tcx> { def_id: DefId, bound_vars: SubstsRef<'tcx>, ) -> Vec>> { - 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 @@ -118,34 +118,27 @@ impl<'tcx> chalk_solve::RustIrDatabase> 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 }; @@ -281,11 +274,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> 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, }) } @@ -406,24 +408,38 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t ) -> Arc>> { 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 }, ), }) } @@ -443,19 +459,61 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t &self, opaque_ty_id: chalk_ir::OpaqueTyId>, ) -> Arc>> { - 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>> + >::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), }) } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 3fcbfd6187c8f..81e7fa4aa3082 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -638,8 +638,16 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders, ) -> chalk_ir::Binders>> { + // `Self` has one binder: + // Binder<&'tcx ty::List>> + // The return type has two: + // Binders<&[Binders>]> + // 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), @@ -648,7 +656,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders { 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 @@ -659,25 +667,34 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders 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) } } @@ -750,6 +767,17 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::TraitBound>> } } +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>> for ty::ProjectionPredicate<'tcx> { diff --git a/src/test/ui/chalkify/arithmetic.rs b/src/test/ui/chalkify/arithmetic.rs new file mode 100644 index 0000000000000..a20acce4c76b2 --- /dev/null +++ b/src/test/ui/chalkify/arithmetic.rs @@ -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; +} diff --git a/src/test/ui/chalkify/trait-objects.rs b/src/test/ui/chalkify/trait-objects.rs new file mode 100644 index 0000000000000..13d9e6a657885 --- /dev/null +++ b/src/test/ui/chalkify/trait-objects.rs @@ -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); +}