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

Opaque higher ranked #1

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
01db8b6
Delay a span bug if we see ty/const generic params during writeback
compiler-errors Jul 22, 2022
c9b21b0
orphan check: remove const generics fixme
lcnr Jul 28, 2022
2634309
update comment
lcnr Jul 29, 2022
ca3d101
Add `Iterator::array_chunks()`
rossmacarthur Jan 2, 2022
f548518
Use `array::IntoIter` for the `ArrayChunks` remainder
rossmacarthur Feb 4, 2022
ef72349
Remove `array::IntoIter::with_partial` -- an artifact of the past, on…
WaffleLapkin Aug 1, 2022
b8b1486
Forward `ArrayChunks::next{,_back}` to `try_{for_each,rfold}`
WaffleLapkin Aug 1, 2022
4db628a
Remove incorrect impl `TrustedLen` for `ArrayChunks`
WaffleLapkin Aug 1, 2022
3102b39
Use `#[track_caller]` to make panic in `Iterator::array_chunks` nicer
WaffleLapkin Aug 1, 2022
37dfb04
Remove `Fuse` from `ArrayChunks` implementation
WaffleLapkin Aug 1, 2022
4c0292c
Simplify `ArrayChunks::is_empty`
WaffleLapkin Aug 1, 2022
475e4ba
Simplify `ArrayChunks::{,r}fold` impls
WaffleLapkin Aug 1, 2022
756bd6e
Use `next_chunk` in `ArrayChunks` impl
WaffleLapkin Aug 2, 2022
2af92bb
Suggest removing `let` if `const let` is used
obeis Aug 3, 2022
accb8e3
Suggest removing `let` if `let const` is used
obeis Aug 3, 2022
b3f32d1
Add ui test for #99910
obeis Aug 3, 2022
eb6b729
address review comments
WaffleLapkin Aug 12, 2022
5fbcde1
fill-in tracking issue for `feature(iter_array_chunks)`
WaffleLapkin Aug 12, 2022
8fa707a
rustc_target: Update some old naming around self contained linking
petrochenkov Aug 3, 2022
6b19a48
`assert_{inhabited,zero_valid,uninit_valid}` intrinsics are safe
tmiasko Aug 13, 2022
68f327b
Merge HTML elements in highlighting when they can be merged together
GuillaumeGomez Aug 11, 2022
33df8a9
Don't generate ident elements as DOM nodes
GuillaumeGomez Aug 12, 2022
6e574e1
Update rustdoc tests
GuillaumeGomez Aug 11, 2022
a9f3e03
Rollup merge of #99582 - compiler-errors:issue-99566, r=cjgillot
Dylan-DPC Aug 14, 2022
92344e3
Rollup merge of #99861 - lcnr:orphan-check-cg, r=jackh726
Dylan-DPC Aug 14, 2022
482a6ea
Rollup merge of #100026 - WaffleLapkin:array-chunks, r=scottmcm
Dylan-DPC Aug 14, 2022
7473484
Rollup merge of #100115 - obeis:issue-99910, r=cjgillot
Dylan-DPC Aug 14, 2022
38bc937
Rollup merge of #100126 - petrochenkov:screname, r=davidtwco
Dylan-DPC Aug 14, 2022
9de9786
Rollup merge of #100487 - tmiasko:assert-safe, r=petrochenkov
Dylan-DPC Aug 14, 2022
4c56655
Auto merge of #100525 - Dylan-DPC:rollup-4cp6nu0, r=Dylan-DPC
bors Aug 14, 2022
801821d
Auto merge of #100429 - GuillaumeGomez:merge-html-elements-together, …
bors Aug 14, 2022
73a3c7e
[REFACTOR] add fn finalize_opaque_types
aliemjay Aug 13, 2022
0329621
[REFACTOR] use OpaqueTypeMap type alias
aliemjay Aug 13, 2022
3a423b7
fix eval_outlives for higher-ranked regions
aliemjay Aug 15, 2022
fcbd6a3
support higher-ranked region in member constraints
aliemjay Aug 15, 2022
e6b62a0
support higher-ranked regions in opaque type inference
aliemjay Aug 15, 2022
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
56 changes: 46 additions & 10 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,25 @@ pub(crate) struct RegionDefinition<'tcx> {

/// If this is 'static or an early-bound region, then this is
/// `Some(X)` where `X` is the name of the region.
///
/// Use the method `Self::external_name` for more flexibility.
pub(crate) external_name: Option<ty::Region<'tcx>>,
}

impl<'tcx> RegionDefinition<'tcx> {
/// Gets the name of a universal region (including placeholders).
/// Returns `None` if this is an existential variable.
pub fn external_name(&self, tcx: TyCtxt<'tcx>) -> Option<ty::Region<'tcx>> {
match self.origin {
NllRegionVariableOrigin::FreeRegion => self.external_name,
NllRegionVariableOrigin::Placeholder(placeholder) => {
Some(tcx.mk_region(ty::RePlaceholder(placeholder)))
}
NllRegionVariableOrigin::Existential { .. } => None,
}
}
}

/// N.B., the variants in `Cause` are intentionally ordered. Lower
/// values are preferred when it comes to error messages. Do not
/// reorder willy nilly.
Expand Down Expand Up @@ -712,16 +728,28 @@ impl<'tcx> RegionInferenceContext<'tcx> {
*c_r = self.scc_representatives[scc];
}

// The 'member region' in a member constraint is part of the
// hidden type, which must be in the root universe. Therefore,
// it cannot have any placeholders in its value.
assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT);
debug_assert!(
self.scc_values.placeholders_contained_in(scc).next().is_none(),
"scc {:?} in a member constraint has placeholder value: {:?}",
scc,
self.scc_values.region_value_str(scc),
);
// The 'member region' may have a placeholder region in its value.
// Consider the inner opaque type `impl Sized` in:
// `fn test() -> impl for<'a> Trait<'a, Ty = impl Sized + 'a>`.
// Here choice_regions = ['static, Placeholder('a, U1)].
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
let Some(&choice) = choice_regions
.iter()
.find(|&&choice| self.eval_equal(choice, self.scc_representatives[scc]))
else {
debug!("failed higher-ranked member constraint");
return false;
};

self.member_constraints_applied.push(AppliedMemberConstraint {
member_region_scc: scc,
min_choice: choice,
member_constraint_index,
});

debug!(?choice, "higher-ranked");
return true;
}

// The existing value for `scc` is a lower-bound. This will
// consist of some set `{P} + {LB}` of points `{P}` and
Expand Down Expand Up @@ -1360,6 +1388,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
return self.eval_outlives(sup_region, self.universal_regions.fr_static);
}

// Check `sup_region` contains all the placeholder regions in `sub_region`.
if !self.scc_values.contains_placeholders(sup_region_scc, sub_region_scc) {
debug!(
"eval_outlives: returning false because sub region contains a placeholder region not present in super"
);
return false;
}

// Both the `sub_region` and `sup_region` consist of the union
// of some number of universal regions (along with the union
// of various points in the CFG; ignore those points for
Expand Down
73 changes: 52 additions & 21 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::opaque_types::OpaqueTypeMap;
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
Expand Down Expand Up @@ -62,23 +63,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
opaque_ty_decls: OpaqueTypeMap<'tcx>,
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
for (opaque_type_key, decl) in opaque_ty_decls {
let substs = opaque_type_key.substs;
debug!(?concrete_type, ?substs);
debug!(?decl.hidden_type, ?substs);

let mut subst_regions = vec![self.universal_regions.fr_static];
let universal_substs = infcx.tcx.fold_regions(substs, |region, _| {
if let ty::RePlaceholder(..) = region.kind() {
// Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
return region;
let (vid, scc) = match region.kind() {
ty::ReVar(vid) => (vid, self.constraint_sccs.scc(vid)),
_ => bug!("expected nll var"),
};
trace!(?vid, ?scc);

// Special handling of higher-ranked regions. These appear in the substs of the
// inner opaque type `impl Sized` in:
// `fn test() -> impl for<'a> Trait<'a, Ty = impl Sized + 'a>`
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
subst_regions.push(vid);
return self.definitions[vid]
.external_name(infcx.tcx)
.expect("higher-ranked existential region found in opaque type substs");
}
let vid = self.to_region_vid(region);
trace!(?vid);
let scc = self.constraint_sccs.scc(vid);
trace!(?scc);

match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
}) {
Expand All @@ -90,7 +99,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
None => {
subst_regions.push(vid);
infcx.tcx.sess.delay_span_bug(
concrete_type.span,
decl.hidden_type.span,
"opaque type with non-universal region substs",
);
infcx.tcx.lifetimes.re_static
Expand All @@ -102,13 +111,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
subst_regions.dedup();

let universal_concrete_type =
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
infcx.tcx.fold_regions(decl.hidden_type, |region, _| match *region {
ty::ReVar(vid) => subst_regions
.iter()
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
.and_then(|ur_vid| self.definitions[*ur_vid].external_name(infcx.tcx))
.unwrap_or(infcx.tcx.lifetimes.re_root_empty),
_ => region,
_ => bug!("expected nll var"),
});

debug!(?universal_concrete_type, ?universal_substs);
Expand All @@ -118,7 +127,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let ty = infcx.infer_opaque_definition_from_instantiation(
opaque_type_key,
universal_concrete_type,
origin,
decl.origin,
);
// Sometimes two opaque types are the same only after we remap the generic parameters
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
Expand All @@ -128,19 +137,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if prev.ty != ty {
if !ty.references_error() {
prev.report_mismatch(
&OpaqueHiddenType { ty, span: concrete_type.span },
&OpaqueHiddenType { ty, span: decl.hidden_type.span },
infcx.tcx,
);
}
prev.ty = infcx.tcx.ty_error();
}
// Pick a better span if there is one.
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
prev.span = prev.span.substitute_dummy(concrete_type.span);
prev.span = prev.span.substitute_dummy(decl.hidden_type.span);
} else {
result.insert(
opaque_type_key.def_id,
OpaqueHiddenType { ty, span: concrete_type.span },
OpaqueHiddenType { ty, span: decl.hidden_type.span },
);
}
}
Expand All @@ -159,6 +168,25 @@ impl<'tcx> RegionInferenceContext<'tcx> {
{
tcx.fold_regions(ty, |region, _| match *region {
ty::ReVar(vid) => {
let scc = self.constraint_sccs.scc(vid);

// Special handling of higher-ranked regions.
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
// If the region contains a single placeholder then they're equal.
if let Some((0, placeholder)) =
self.scc_values.placeholders_contained_in(scc).enumerate().last()
{
// HACK: we convert named placeholders to free regions for better errors.
// Otherwise, this is incorrect.
if let bound_region @ ty::BrNamed(scope, _) = placeholder.name {
return tcx
.mk_region(ty::ReFree(ty::FreeRegion { scope, bound_region }));
}
}
// Fallback: this will produce a cryptic error message.
return region;
}

// Find something that we can name
let upper_bound = self.approx_universal_upper_bound(vid);
let upper_bound = &self.definitions[upper_bound];
Expand Down Expand Up @@ -384,7 +412,7 @@ fn check_opaque_type_parameter_valid(
return false;
}
GenericArgKind::Lifetime(lt) => {
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_) | ty::RePlaceholder(_))
}
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
};
Expand Down Expand Up @@ -494,9 +522,12 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
ty::ReErased => return r,

// The regions that we expect from borrow checking.
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
ty::ReEarlyBound(_)
| ty::ReFree(_)
| ty::RePlaceholder(_)
| ty::ReEmpty(ty::UniverseIndex::ROOT) => {}

ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
ty::ReEmpty(_) | ty::ReVar(_) => {
// All of the regions in the type should either have been
// erased by writeback, or mapped back to named regions by
// borrow checking.
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_borrowck/src/region_infer/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,22 @@ impl<N: Idx> RegionValues<N> {
}
}

/// Returns `true` if `sup_region` contains all the placeholder elements that
/// `sub_region` contains.
pub(crate) fn contains_placeholders(&self, sup_region: N, sub_region: N) -> bool {
if let Some(sub_row) = self.placeholders.row(sub_region) {
if let Some(sup_row) = self.placeholders.row(sup_region) {
sup_row.superset(sub_row)
} else {
// sup row is empty, so sub row must be empty
sub_row.is_empty()
}
} else {
// sub row is empty, always true
true
}
}

/// Returns the locations contained within a given region `r`.
pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
self.points.row(r).into_iter().flat_map(move |set| {
Expand Down
Loading