borrowck: more eagerly prepopulate opaques
This commit is contained in:
parent
5f044f3528
commit
24ee32cf70
@ -182,6 +182,12 @@ fn do_mir_borrowck<'tcx>(
|
||||
nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted);
|
||||
let body = &body_owned; // no further changes
|
||||
|
||||
// FIXME(-Znext-solver): A bit dubious that we're only registering
|
||||
// predefined opaques in the typeck root.
|
||||
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
||||
infcx.register_predefined_opaques_for_next_solver(def);
|
||||
}
|
||||
|
||||
let location_table = LocationTable::new(body);
|
||||
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
|
||||
@ -488,6 +494,28 @@ pub(crate) fn next_nll_region_var<F>(
|
||||
|
||||
next_region
|
||||
}
|
||||
|
||||
/// With the new solver we prepopulate the opaque type storage during
|
||||
/// MIR borrowck with the hidden types from HIR typeck. This is necessary
|
||||
/// to avoid ambiguities as earlier goals can rely on the hidden type
|
||||
/// of an opaque which is only constrained by a later goal.
|
||||
fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) {
|
||||
let tcx = self.tcx;
|
||||
// OK to use the identity arguments for each opaque type key, since
|
||||
// we remap opaques from HIR typeck back to their definition params.
|
||||
for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) {
|
||||
// HIR typeck did not infer the regions of the opaque, so we instantiate
|
||||
// them with fresh inference variables.
|
||||
let (key, hidden_ty) = tcx.fold_regions(data, |_, _| {
|
||||
self.next_nll_region_var_in_universe(
|
||||
NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
ty::UniverseIndex::ROOT,
|
||||
)
|
||||
});
|
||||
|
||||
self.inject_new_hidden_type_unchecked(key, hidden_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
|
||||
|
@ -24,7 +24,6 @@
|
||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
@ -1028,7 +1027,7 @@ fn new(
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
) -> Self {
|
||||
let mut checker = Self {
|
||||
Self {
|
||||
infcx,
|
||||
last_span: body.span,
|
||||
body,
|
||||
@ -1039,74 +1038,6 @@ fn new(
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
reported_errors: Default::default(),
|
||||
};
|
||||
|
||||
// FIXME(-Znext-solver): A bit dubious that we're only registering
|
||||
// predefined opaques in the typeck root.
|
||||
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
||||
checker.register_predefined_opaques_for_next_solver();
|
||||
}
|
||||
|
||||
checker
|
||||
}
|
||||
|
||||
pub(super) fn register_predefined_opaques_for_next_solver(&mut self) {
|
||||
// OK to use the identity arguments for each opaque type key, since
|
||||
// we remap opaques from HIR typeck back to their definition params.
|
||||
let opaques: Vec<_> = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(self.body.source.def_id().expect_local())
|
||||
.concrete_opaque_types
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, *v))
|
||||
.collect();
|
||||
|
||||
let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
|
||||
self.infcx.next_nll_region_var_in_universe(
|
||||
NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
ty::UniverseIndex::ROOT,
|
||||
)
|
||||
});
|
||||
|
||||
let param_env = self.param_env;
|
||||
let result = self.fully_perform_op(
|
||||
Locations::All(self.body.span),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|ocx| {
|
||||
let mut obligations = Vec::new();
|
||||
for (opaque_type_key, hidden_ty) in renumbered_opaques {
|
||||
let cause = ObligationCause::dummy();
|
||||
ocx.infcx.insert_hidden_type(
|
||||
opaque_type_key,
|
||||
&cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
&mut obligations,
|
||||
)?;
|
||||
|
||||
ocx.infcx.add_item_bounds_for_hidden_type(
|
||||
opaque_type_key.def_id.to_def_id(),
|
||||
opaque_type_key.args,
|
||||
cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
&mut obligations,
|
||||
);
|
||||
}
|
||||
|
||||
ocx.register_obligations(obligations);
|
||||
Ok(())
|
||||
},
|
||||
"register pre-defined opaques",
|
||||
),
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
self.infcx
|
||||
.dcx()
|
||||
.span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,6 +485,19 @@ fn register_hidden_type(
|
||||
Ok(InferOk { value: (), obligations })
|
||||
}
|
||||
|
||||
/// Insert a hidden type into the opaque type storage, making sure
|
||||
/// it hasn't previously been defined. This does not emit any
|
||||
/// constraints and it's the responsibility of the caller to make
|
||||
/// sure that the item bounds of the opaque are checked.
|
||||
pub fn inject_new_hidden_type_unchecked(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
hidden_ty: OpaqueHiddenType<'tcx>,
|
||||
) {
|
||||
let prev = self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty);
|
||||
assert_eq!(prev, None);
|
||||
}
|
||||
|
||||
/// Insert a hidden type into the opaque type storage, equating it
|
||||
/// with any previous entries if necessary.
|
||||
///
|
||||
|
@ -2,6 +2,9 @@
|
||||
// when there are multiple inputs. The `dyn Bar` should default to `+
|
||||
// 'static`. This used to erroneously generate an error (cc #62517).
|
||||
//
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@ check-pass
|
||||
|
||||
trait Foo {
|
||||
|
@ -1,3 +1,6 @@
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@ check-pass
|
||||
|
||||
pub fn main() {}
|
||||
|
@ -1,3 +1,6 @@
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@ check-pass
|
||||
|
||||
use std::io::Write;
|
||||
|
@ -1,14 +0,0 @@
|
||||
error: internal compiler error: error performing operation: query type op
|
||||
--> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
|
||||
|
|
||||
LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note:
|
||||
--> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
|
||||
|
|
||||
LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
query stack during panic:
|
||||
end of query stack
|
@ -1,29 +0,0 @@
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@[next] failure-status: 101
|
||||
//@[next] known-bug: unknown
|
||||
//@[next] normalize-stderr-test "note: .*\n\n" -> ""
|
||||
//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
|
||||
//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
|
||||
//@[next] normalize-stderr-test "delayed at .*" -> ""
|
||||
//@[next] rustc-env:RUST_BACKTRACE=0
|
||||
|
||||
#![feature(trait_upcasting, type_alias_impl_trait)]
|
||||
|
||||
trait Super {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Sub: Super {}
|
||||
|
||||
impl<T: ?Sized> Super for T {
|
||||
type Assoc = i32;
|
||||
}
|
||||
|
||||
type Foo = impl Sized;
|
||||
|
||||
fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
x //[current]~ mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,11 +1,11 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/illegal-upcast-from-impl-opaque.rs:26:5
|
||||
--> $DIR/upcast-defining-opaque.rs:21:5
|
||||
|
|
||||
LL | type Foo = impl Sized;
|
||||
| ---------- the found opaque type
|
||||
LL |
|
||||
LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ----------------------- expected `&dyn Super<Assoc = i32>` because of return type
|
||||
LL | fn upcast(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ----------------------- expected `&dyn Super<Assoc = i32>` because of return type
|
||||
LL | x
|
||||
| ^ expected trait `Super`, found trait `Sub`
|
||||
|
|
24
tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs
Normal file
24
tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs
Normal file
@ -0,0 +1,24 @@
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] check-pass
|
||||
|
||||
#![feature(trait_upcasting, type_alias_impl_trait)]
|
||||
|
||||
trait Super {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Sub: Super {}
|
||||
|
||||
impl<T: ?Sized> Super for T {
|
||||
type Assoc = i32;
|
||||
}
|
||||
|
||||
type Foo = impl Sized;
|
||||
|
||||
fn upcast(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
x //[current]~ mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user