-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Do two passes of handle_opaque_type_uses_next
#147249
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
Changes from 4 commits
db3c9b6
9a5cef1
c6c58e3
a3fbae5
283ad66
8b17827
d51f09e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,29 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
/// inference variables. | ||
/// | ||
/// It then uses these defining uses to guide inference for all other uses. | ||
/// | ||
/// Unlike `handle_opaque_type_uses_next`, this does not report errors. | ||
#[instrument(level = "debug", skip(self))] | ||
pub(super) fn try_handle_opaque_type_uses_next(&mut self) { | ||
// We clone the opaques instead of stealing them here as they are still used for | ||
// normalization in the next generation trait solver. | ||
let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types(); | ||
for entry in &mut opaque_types { | ||
*entry = self.resolve_vars_if_possible(*entry); | ||
} | ||
debug!(?opaque_types); | ||
jackh726 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
self.compute_definition_site_hidden_types(&opaque_types, true); | ||
} | ||
|
||
/// This takes all the opaque type uses during HIR typeck. It first computes | ||
/// the concrete hidden type by iterating over all defining uses. | ||
/// | ||
/// A use during HIR typeck is defining if all non-lifetime arguments are | ||
/// unique generic parameters and the hidden type does not reference any | ||
/// inference variables. | ||
/// | ||
/// It then uses these defining uses to guide inference for all other uses. | ||
#[instrument(level = "debug", skip(self))] | ||
pub(super) fn handle_opaque_type_uses_next(&mut self) { | ||
// We clone the opaques instead of stealing them here as they are still used for | ||
|
@@ -35,22 +58,22 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
} | ||
debug!(?opaque_types); | ||
|
||
self.compute_definition_site_hidden_types(&opaque_types); | ||
self.apply_definition_site_hidden_types(&opaque_types); | ||
self.compute_definition_site_hidden_types(&opaque_types, false); | ||
} | ||
} | ||
|
||
#[derive(Copy, Clone, Debug)] | ||
enum UsageKind<'tcx> { | ||
None, | ||
NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>), | ||
UnconstrainedHiddenType(OpaqueHiddenType<'tcx>), | ||
HasDefiningUse, | ||
HasDefiningUse(OpaqueHiddenType<'tcx>), | ||
} | ||
|
||
impl<'tcx> UsageKind<'tcx> { | ||
fn merge(&mut self, other: UsageKind<'tcx>) { | ||
match (&*self, &other) { | ||
(UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(), | ||
(UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(), | ||
(UsageKind::None, _) => *self = other, | ||
// When mergining non-defining uses, prefer earlier ones. This means | ||
// the error happens as early as possible. | ||
|
@@ -64,7 +87,7 @@ impl<'tcx> UsageKind<'tcx> { | |
// intended to be defining. | ||
( | ||
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..), | ||
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse, | ||
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_), | ||
) => *self = other, | ||
} | ||
} | ||
|
@@ -74,6 +97,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
fn compute_definition_site_hidden_types( | ||
&mut self, | ||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], | ||
first_pass: bool, | ||
jackh726 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
) { | ||
let tcx = self.tcx; | ||
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() | ||
|
@@ -88,19 +112,50 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
_ => unreachable!("not opaque or generator: {def_id:?}"), | ||
} | ||
|
||
// We do actually need to check this the second pass (we can't just | ||
// store this), because we can go from `UnconstrainedHiddenType` to | ||
// `HasDefiningUse` (because of fallback) | ||
Comment on lines
+112
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can also just go from no uses to a defining use due to fallback, e.g. if you have soem There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it could also be |
||
let mut usage_kind = UsageKind::None; | ||
for &(opaque_type_key, hidden_type) in opaque_types { | ||
if opaque_type_key.def_id != def_id { | ||
continue; | ||
} | ||
|
||
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type)); | ||
if let UsageKind::HasDefiningUse = usage_kind { | ||
|
||
if let UsageKind::HasDefiningUse(..) = usage_kind { | ||
break; | ||
} | ||
} | ||
|
||
if let UsageKind::HasDefiningUse(ty) = usage_kind { | ||
for &(opaque_type_key, hidden_type) in opaque_types { | ||
if opaque_type_key.def_id != def_id { | ||
continue; | ||
} | ||
|
||
let expected = EarlyBinder::bind(ty.ty).instantiate(tcx, opaque_type_key.args); | ||
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); | ||
} | ||
|
||
let prev = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty); | ||
|
||
// We do want to insert opaque types the first pass, because | ||
// we want to equate them. So, the second pass (where we | ||
// report errors) may have a hidden type inserted. | ||
if first_pass { | ||
assert!(prev.is_none()); | ||
} | ||
} | ||
lcnr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// If this the first pass (`try_handle_opaque_type_uses_next`), | ||
// then do not report any errors. | ||
jackh726 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
if first_pass { | ||
continue; | ||
} | ||
|
||
let guar = match usage_kind { | ||
UsageKind::HasDefiningUse(_) => continue, | ||
UsageKind::None => { | ||
if let Some(guar) = self.tainted_by_errors() { | ||
guar | ||
|
@@ -137,7 +192,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
.emit() | ||
} | ||
} | ||
UsageKind::HasDefiningUse => continue, | ||
}; | ||
|
||
self.typeck_results | ||
|
@@ -148,6 +202,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
} | ||
} | ||
|
||
#[tracing::instrument(skip(self), ret)] | ||
fn consider_opaque_type_use( | ||
&mut self, | ||
jackh726 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
opaque_type_key: OpaqueTypeKey<'tcx>, | ||
|
@@ -161,11 +216,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
) { | ||
match err { | ||
NonDefiningUseReason::Tainted(guar) => { | ||
self.typeck_results.borrow_mut().hidden_types.insert( | ||
opaque_type_key.def_id, | ||
OpaqueHiddenType::new_error(self.tcx, guar), | ||
); | ||
return UsageKind::HasDefiningUse; | ||
return UsageKind::HasDefiningUse(OpaqueHiddenType::new_error(self.tcx, guar)); | ||
} | ||
_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type), | ||
}; | ||
|
@@ -193,27 +244,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { | |
self.tcx, | ||
DefiningScopeKind::HirTypeck, | ||
); | ||
|
||
let prev = self | ||
.typeck_results | ||
.borrow_mut() | ||
.hidden_types | ||
.insert(opaque_type_key.def_id, hidden_type); | ||
assert!(prev.is_none()); | ||
UsageKind::HasDefiningUse | ||
} | ||
|
||
fn apply_definition_site_hidden_types( | ||
&mut self, | ||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], | ||
) { | ||
let tcx = self.tcx; | ||
for &(key, hidden_type) in opaque_types { | ||
let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap(); | ||
|
||
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); | ||
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); | ||
} | ||
UsageKind::HasDefiningUse(hidden_type) | ||
} | ||
|
||
/// We may in theory add further uses of an opaque after cloning the opaque | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//@ revisions: current next | ||
//@ ignore-compare-mode-next-solver (explicit revisions) | ||
//@[next] compile-flags: -Znext-solver | ||
//@ check-pass | ||
|
||
// Regression test for trait-system-refactor-initiative#240. Hidden types should | ||
// equate *before* inference var fallback, otherwise we can get mismatched types. | ||
|
||
jackh726 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#[derive(Clone, Copy)] | ||
struct FileSystem; | ||
impl FileSystem { | ||
fn build<T>(self, commands: T) -> Option<impl Sized> { | ||
match false { | ||
true => Some(commands), | ||
false => { | ||
drop(match self.build::<_>(commands) { | ||
Some(x) => x, | ||
None => return None, | ||
}); | ||
panic!() | ||
}, | ||
} | ||
} | ||
} | ||
|
||
fn main() {} |
Uh oh!
There was an error while loading. Please reload this page.