Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate projection bounds and predicates #73905

Merged
merged 34 commits into from
Oct 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0eb87ed
Rename projection_predicates to item_bounds
matthewjasper Jun 23, 2020
a7ead3b
Move item_bounds to typeck::collect
matthewjasper Jun 23, 2020
d297147
Split bounds from predicates
matthewjasper Jun 24, 2020
f958e6c
Separate bounds and predicates for associated/opaque types
matthewjasper Jun 27, 2020
87f2f42
Make projection wf check the predicates for the projection
matthewjasper Jun 28, 2020
b3057f4
Check projections are well-formed when using projection candidates
matthewjasper Jun 28, 2020
5b279c8
Check opaque types satisfy their bounds
matthewjasper Jun 28, 2020
1b07991
Check associated type bounds for object safety violations
matthewjasper Jun 28, 2020
d4d9e7f
Remove unused part of return value from `replace_bound_vars_with_plac…
matthewjasper Jun 28, 2020
0a76584
Move some code from rustc_typeck to rustc_trait_selection
matthewjasper Jun 28, 2020
2bdf723
Ensure that associated types for trait objects satisfy their bounds
matthewjasper Jun 28, 2020
042464f
Fix tests and bootstrap
matthewjasper Jun 29, 2020
0dda415
Fix tools
matthewjasper Jun 30, 2020
21eccbb
Fix ICE
matthewjasper Jul 1, 2020
8787090
Address review comments
matthewjasper Jul 2, 2020
582ccec
Remove predicates on associated types from traits
matthewjasper Jul 4, 2020
f52b2d8
Avoid cycle in nested obligations for object candidate
matthewjasper Jul 5, 2020
bc08b79
Fix bugs in evaluating WellFormed predicates
matthewjasper Jul 22, 2020
cfee495
Handle multiple applicable projection candidates
matthewjasper Jul 23, 2020
34e5a49
Normalize projection bounds when considering candidates
matthewjasper Jul 24, 2020
596d6c4
Avoid cycle with projections from object types
matthewjasper Jul 24, 2020
0dfa6ff
Avoid cycles from projection bounds
matthewjasper Jul 25, 2020
ed32482
Handle multiple trait-def projection candidates
matthewjasper Jul 25, 2020
6c4feb6
Fix bootstrap
matthewjasper Jul 25, 2020
e297652
Don't immediately error for recursive projections
matthewjasper Jul 25, 2020
d08ab94
Fix rebase
matthewjasper Aug 14, 2020
e674cf0
Normalize super trait bounds when confirming object candidates
matthewjasper Aug 14, 2020
e42c979
Don't require lifetime super-bounds on traits apply to trait objects …
matthewjasper Aug 15, 2020
852073a
Deduplicate item bounds after normalization
matthewjasper Aug 15, 2020
27534b3
Fix rebase
matthewjasper Sep 6, 2020
1db284e
Avoid creating useless projection predicate
matthewjasper Sep 7, 2020
022c148
Fix tests from rebase
matthewjasper Sep 7, 2020
c9eeb60
Deduplicate some code
matthewjasper Oct 5, 2020
69fc6d8
Fix NLL compare mode tests
matthewjasper Oct 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,17 +432,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.with_catch_scope(body.id, |this| {
let mut block = this.lower_block_noalloc(body, true);

let try_span = this.mark_span_with_reason(
DesugaringKind::TryBlock,
body.span,
this.allow_try_trait.clone(),
);

// Final expression of the block (if present) or `()` with span at the end of block
let tail_expr = block
.expr
.take()
.unwrap_or_else(|| this.expr_unit(this.sess.source_map().end_point(try_span)));
let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {
(
this.mark_span_with_reason(
DesugaringKind::TryBlock,
expr.span,
this.allow_try_trait.clone(),
),
expr,
)
} else {
let try_span = this.mark_span_with_reason(
DesugaringKind::TryBlock,
this.sess.source_map().end_point(body.span),
this.allow_try_trait.clone(),
);

(try_span, this.expr_unit(try_span))
};

let ok_wrapped_span =
this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
Expand Down Expand Up @@ -1553,7 +1561,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::LangItem::TryFromError,
unstable_span,
from_expr,
try_span,
unstable_span,
);
let thin_attrs = ThinVec::from(attrs);
let catch_scope = self.catch_scopes.last().copied();
Expand Down
38 changes: 15 additions & 23 deletions compiler/rustc_error_codes/src/error_codes/E0284.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,29 @@ as the `collect` method for `Iterator`s.
For example:

```compile_fail,E0284
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change to this file? Might be better as a separate PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current example doesn't have the right error code any more.

fn foo() -> Result<bool, ()> {
let results = [Ok(true), Ok(false), Err(())].iter().cloned();
let v: Vec<bool> = results.collect()?;
// Do things with v...
Ok(true)
fn main() {
let n: u32 = 1;
let mut d: u64 = 2;
d = d + n.into();
}
```

Here we have an iterator `results` over `Result<bool, ()>`.
Hence, `results.collect()` can return any type implementing
`FromIterator<Result<bool, ()>>`. On the other hand, the
`?` operator can accept any type implementing `Try`.
Here we have an addition of `d` and `n.into()`. Hence, `n.into()` can return
any type `T` where `u64: Add<T>`. On the other hand, the `into` method can
return any type where `u32: Into<T>`.

The author of this code probably wants `collect()` to return a
`Result<Vec<bool>, ()>`, but the compiler can't be sure
that there isn't another type `T` implementing both `Try` and
`FromIterator<Result<bool, ()>>` in scope such that
`T::Ok == Vec<bool>`. Hence, this code is ambiguous and an error
is returned.
The author of this code probably wants `into()` to return a `u64`, but the
compiler can't be sure that there isn't another type `T` where both
`u32: Into<T>` and `u64: Add<T>`.

To resolve this error, use a concrete type for the intermediate expression:

```
fn foo() -> Result<bool, ()> {
let results = [Ok(true), Ok(false), Err(())].iter().cloned();
let v = {
let temp: Result<Vec<bool>, ()> = results.collect();
temp?
};
// Do things with v...
Ok(true)
fn main() {
let n: u32 = 1;
let mut d: u64 = 2;
let m: u64 = n.into();
d = d + m;
}
```

Expand Down
11 changes: 4 additions & 7 deletions compiler/rustc_infer/src/infer/higher_ranked/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! the end of the file for details.

use super::combine::CombineFields;
use super::{HigherRankedType, InferCtxt, PlaceholderMap};
use super::{HigherRankedType, InferCtxt};

use crate::infer::CombinedSnapshot;
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
Expand Down Expand Up @@ -33,7 +33,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
self.infcx.commit_if_ok(|_| {
// First, we instantiate each bound region in the supertype with a
// fresh placeholder region.
let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(&b);
let b_prime = self.infcx.replace_bound_vars_with_placeholders(&b);

// Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables --
Expand Down Expand Up @@ -66,10 +66,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// the [rustc dev guide].
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
pub fn replace_bound_vars_with_placeholders<T>(
&self,
binder: &ty::Binder<T>,
) -> (T, PlaceholderMap<'tcx>)
pub fn replace_bound_vars_with_placeholders<T>(&self, binder: &ty::Binder<T>) -> T
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be another diff worth splitting into a separate PR since it's small and self-contained from what I can see.

where
T: TypeFoldable<'tcx>,
{
Expand Down Expand Up @@ -122,7 +119,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
next_universe, binder, result, map,
);

(result, map)
result
}

/// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
Expand Down
9 changes: 2 additions & 7 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,6 @@ pub struct InferCtxt<'a, 'tcx> {
universe: Cell<ty::UniverseIndex>,
}

/// A map returned by `replace_bound_vars_with_placeholders()`
/// indicating the placeholder region that each late-bound region was
/// replaced with.
pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;

/// See the `error_reporting` module for more details.
#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)]
pub enum ValuePairs<'tcx> {
Expand Down Expand Up @@ -992,7 +987,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}

Some(self.commit_if_ok(|_snapshot| {
let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
let ty::SubtypePredicate { a_is_expected, a, b } =
self.replace_bound_vars_with_placeholders(&predicate);

let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
Expand All @@ -1007,7 +1002,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
) -> UnitResult<'tcx> {
self.commit_if_ok(|_snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), _) =
let ty::OutlivesPredicate(r_a, r_b) =
self.replace_bound_vars_with_placeholders(&predicate);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
RelateRegionParamBound(cause.span)
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/outlives/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
assoc_item_def_id: DefId,
) -> impl Iterator<Item = ty::Region<'tcx>> {
let tcx = self.tcx;
let predicates = tcx.projection_predicates(assoc_item_def_id);
predicates
let bounds = tcx.item_bounds(assoc_item_def_id);
bounds
.into_iter()
.filter_map(|p| p.to_opt_type_outlives())
.filter_map(|p| p.no_bound_vars())
Expand Down
31 changes: 18 additions & 13 deletions compiler/rustc_infer/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
use rustc_span::Span;

pub fn anonymize_predicate<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down Expand Up @@ -94,7 +93,11 @@ pub fn elaborate_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
) -> Elaborator<'tcx> {
let obligations = predicates.map(|predicate| predicate_obligation(predicate, None)).collect();
let obligations = predicates
.map(|predicate| {
predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy())
})
.collect();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably audit the elaborate_predicates calls to see if we can further avoid ty::ParamEnv::empty() calls (if you haven't done already, and should be done as a follow up).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like only the predicates from the obligations returned by elaborate_predicates are used.

elaborate_obligations(tcx, obligations)
}

Expand All @@ -109,15 +112,10 @@ pub fn elaborate_obligations<'tcx>(

fn predicate_obligation<'tcx>(
predicate: ty::Predicate<'tcx>,
span: Option<Span>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
) -> PredicateObligation<'tcx> {
let cause = if let Some(span) = span {
ObligationCause::dummy_with_span(span)
} else {
ObligationCause::dummy()
};

Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }
Obligation { cause, param_env, recursion_depth: 0, predicate }
}

impl Elaborator<'tcx> {
Expand All @@ -133,10 +131,11 @@ impl Elaborator<'tcx> {
// Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id());

let obligations = predicates.predicates.iter().map(|&(pred, span)| {
let obligations = predicates.predicates.iter().map(|&(pred, _)| {
predicate_obligation(
pred.subst_supertrait(tcx, &ty::Binder::bind(data.trait_ref)),
Some(span),
obligation.param_env,
obligation.cause.clone(),
)
});
debug!("super_predicates: data={:?}", data);
Expand Down Expand Up @@ -233,7 +232,13 @@ impl Elaborator<'tcx> {
})
.map(|predicate_kind| predicate_kind.to_predicate(tcx))
.filter(|&predicate| visited.insert(predicate))
.map(|predicate| predicate_obligation(predicate, None)),
.map(|predicate| {
predicate_obligation(
predicate,
obligation.param_env,
obligation.cause.clone(),
)
}),
);
}
ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
ty::Adt(def, _) => check_must_use_def(cx, def.did, span, descr_pre, descr_post),
ty::Opaque(def, _) => {
let mut has_emitted = false;
for (predicate, _) in cx.tcx.predicates_of(def).predicates {
for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateAtom::Trait(ref poly_trait_predicate, _) =
predicate.skip_binders()
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.tables
.inferred_outlives
.get(self, item_id)
.map(|predicates| predicates.decode((self, tcx)))
.map(|predicates| tcx.arena.alloc_from_iter(predicates.decode((self, tcx))))
.unwrap_or_default()
}

Expand All @@ -949,6 +949,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
self.root.tables.super_predicates.get(self, item_id).unwrap().decode((self, tcx))
}

fn get_explicit_item_bounds(
&self,
item_id: DefIndex,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
self.root
.tables
.explicit_item_bounds
.get(self, item_id)
.map(|bounds| tcx.arena.alloc_from_iter(bounds.decode((self, tcx))))
.unwrap_or_default()
}

fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
explicit_predicates_of => { cdata.get_explicit_predicates(def_id.index, tcx) }
inferred_outlives_of => { cdata.get_inferred_outlives(def_id.index, tcx) }
super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
trait_def => { cdata.get_trait_def(def_id.index, tcx.sess) }
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
adt_destructor => {
Expand Down
18 changes: 16 additions & 2 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,14 @@ impl EncodeContext<'a, 'tcx> {
record!(self.tables.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id));
}

fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
let bounds = self.tcx.explicit_item_bounds(def_id);
if !bounds.is_empty() {
record!(self.tables.explicit_item_bounds[def_id] <- bounds);
}
}

fn encode_info_for_trait_item(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
let tcx = self.tcx;
Expand Down Expand Up @@ -1017,7 +1025,10 @@ impl EncodeContext<'a, 'tcx> {
has_self: trait_item.fn_has_self_parameter,
}))
}
ty::AssocKind::Type => EntryKind::AssocType(container),
ty::AssocKind::Type => {
self.encode_explicit_item_bounds(def_id);
EntryKind::AssocType(container)
}
});
record!(self.tables.visibility[def_id] <- trait_item.vis);
record!(self.tables.span[def_id] <- ast_item.span);
Expand Down Expand Up @@ -1255,7 +1266,10 @@ impl EncodeContext<'a, 'tcx> {
hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod,
hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
hir::ItemKind::TyAlias(..) => EntryKind::Type,
hir::ItemKind::OpaqueTy(..) => EntryKind::OpaqueTy,
hir::ItemKind::OpaqueTy(..) => {
self.encode_explicit_item_bounds(def_id);
EntryKind::OpaqueTy
}
hir::ItemKind::Enum(..) => EntryKind::Enum(self.tcx.adt_def(def_id).repr),
hir::ItemKind::Struct(ref struct_def, _) => {
let adt_def = self.tcx.adt_def(def_id);
Expand Down
10 changes: 4 additions & 6 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,11 @@ define_tables! {
generics: Table<DefIndex, Lazy<ty::Generics>>,
explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
// FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate`
// doesn't handle shorthands in its own (de)serialization impls,
// as it's an `enum` for which we want to derive (de)serialization,
// so the `ty::codec` APIs handle the whole `&'tcx [...]` at once.
// Also, as an optimization, a missing entry indicates an empty `&[]`.
inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
// As an optimization, a missing entry indicates an empty `&[]`.
inferred_outlives: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
// As an optimization, a missing entry indicates an empty `&[]`.
explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
Expand Down
Loading