Skip to content

Commit 0eb0df1

Browse files
committed
support non-defining uses in HIR typeck
1 parent 7ee5cf6 commit 0eb0df1

30 files changed

+487
-363
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_middle::ty::{
1717
use rustc_mir_dataflow::points::DenseLocationMap;
1818
use rustc_span::Span;
1919
use rustc_trait_selection::opaque_types::{
20-
InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
20+
NonDefiningUseReason, opaque_type_has_defining_use_args,
2121
};
2222
use rustc_trait_selection::solve::NoSolution;
2323
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -42,7 +42,8 @@ use region_ctxt::RegionCtxt;
4242
/// if there are no `RegionErrors`. If there are region errors, it's likely
4343
/// that errors here are caused by them and don't need to be handled separately.
4444
pub(crate) enum DeferredOpaqueTypeError<'tcx> {
45-
InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>),
45+
/// FIXME(-Znext-solver=no): Only used by the old solver.
46+
InvalidOpaqueTypeArgs(NonDefiningUseReason<'tcx>),
4647
LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>),
4748
UnexpectedHiddenRegion {
4849
/// The opaque type.
@@ -238,7 +239,7 @@ fn collect_defining_uses<'tcx>(
238239
let non_nll_opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |r| {
239240
nll_var_to_universal_region(&rcx, r.as_var()).unwrap_or(r)
240241
});
241-
if let Err(err) = check_opaque_type_parameter_valid(
242+
if let Err(err) = opaque_type_has_defining_use_args(
242243
infcx,
243244
non_nll_opaque_type_key,
244245
hidden_type.span,
@@ -248,11 +249,10 @@ fn collect_defining_uses<'tcx>(
248249
// with `TypingMode::Borrowck`.
249250
if infcx.tcx.use_typing_mode_borrowck() {
250251
match err {
251-
InvalidOpaqueTypeArgs::AlreadyReported(guar) => root_cx
252-
.add_concrete_opaque_type(
253-
opaque_type_key.def_id,
254-
OpaqueHiddenType::new_error(infcx.tcx, guar),
255-
),
252+
NonDefiningUseReason::Tainted(guar) => root_cx.add_concrete_opaque_type(
253+
opaque_type_key.def_id,
254+
OpaqueHiddenType::new_error(infcx.tcx, guar),
255+
),
256256
_ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"),
257257
}
258258
} else {
@@ -676,8 +676,8 @@ impl<'tcx> InferCtxt<'tcx> {
676676
&self,
677677
opaque_type_key: OpaqueTypeKey<'tcx>,
678678
instantiated_ty: OpaqueHiddenType<'tcx>,
679-
) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> {
680-
check_opaque_type_parameter_valid(
679+
) -> Result<Ty<'tcx>, NonDefiningUseReason<'tcx>> {
680+
opaque_type_has_defining_use_args(
681681
self,
682682
opaque_type_key,
683683
instantiated_ty.span,

compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
127127
}
128128

129129
fn non_defining_use_in_defining_scope(&mut self, item_def_id: LocalDefId) {
130+
// We make sure that all opaque types get defined while
131+
// type checking the defining scope, so this error is unreachable
132+
// with the new solver.
133+
assert!(!self.tcx.next_trait_solver_globally());
130134
let guar = self.tcx.dcx().emit_err(TaitForwardCompat2 {
131135
span: self
132136
.tcx
@@ -252,9 +256,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
252256
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
253257
hidden_ty.ty
254258
} else {
255-
// FIXME(-Znext-solver): This should not be necessary and we should
256-
// instead rely on inference variable fallback inside of typeck itself.
257-
259+
assert!(!tcx.next_trait_solver_globally());
258260
// We failed to resolve the opaque type or it
259261
// resolves to itself. We interpret this as the
260262
// no values of the hidden type ever being constructed,
@@ -273,6 +275,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
273275
if let Err(guar) = hir_ty.error_reported() {
274276
Ty::new_error(tcx, guar)
275277
} else {
278+
assert!(!tcx.next_trait_solver_globally());
276279
hir_ty
277280
}
278281
}

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ pub(crate) struct UnconstrainedOpaqueType {
413413
#[derive(Diagnostic)]
414414
#[diag(hir_analysis_tait_forward_compat2)]
415415
#[note]
416-
pub(crate) struct TaitForwardCompat2 {
416+
pub struct TaitForwardCompat2 {
417417
#[primary_span]
418418
pub span: Span,
419419
#[note(hir_analysis_opaque)]

compiler/rustc_hir_analysis/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ mod coherence;
8282
mod collect;
8383
mod constrained_generic_params;
8484
mod delegation;
85-
mod errors;
85+
pub mod errors;
8686
pub mod hir_ty_lowering;
8787
pub mod hir_wf_check;
8888
mod impl_wf_check;

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ fn typeck_with_inspect<'tcx>(
247247

248248
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
249249

250+
// We need to handle opaque types before emitting ambiguity errors as applying
251+
// defining uses may guide type inference.
252+
if fcx.next_trait_solver() {
253+
fcx.handle_opaque_type_uses_next();
254+
}
255+
256+
fcx.select_obligations_where_possible(|_| {});
250257
if let None = fcx.infcx.tainted_by_errors() {
251258
fcx.report_ambiguity_errors();
252259
}

compiler/rustc_hir_typeck/src/opaque_types.rs

Lines changed: 217 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,221 @@
1-
use super::FnCtxt;
1+
use rustc_hir::def::DefKind;
2+
use rustc_hir_analysis::errors::TaitForwardCompat2;
3+
use rustc_infer::traits::ObligationCause;
4+
use rustc_middle::ty::{
5+
self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, TypeVisitableExt,
6+
TypingMode,
7+
};
8+
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
9+
use rustc_trait_selection::opaque_types::{
10+
NonDefiningUseReason, opaque_type_has_defining_use_args,
11+
};
12+
use rustc_trait_selection::solve;
13+
use tracing::{debug, instrument};
14+
15+
use crate::FnCtxt;
16+
217
impl<'tcx> FnCtxt<'_, 'tcx> {
18+
/// This takes all the opaque type uses during HIR typeck. It first computes
19+
/// the concrete hidden type by iterating over all defining uses.
20+
///
21+
/// A use during HIR typeck is defining if all non-lifetime arguments are
22+
/// unique generic parameters and the hidden type does not reference any
23+
/// inference variables.
24+
///
25+
/// It then uses these defining uses to guide inference for all other uses.
26+
#[instrument(level = "debug", skip(self))]
27+
pub(super) fn handle_opaque_type_uses_next(&mut self) {
28+
// We clone the opaques instead of stealing them here as they are still used for
29+
// normalization in the next generation trait solver.
30+
let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types();
31+
let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
32+
let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
33+
debug_assert_eq!(prev, None);
34+
for entry in &mut opaque_types {
35+
*entry = self.resolve_vars_if_possible(*entry);
36+
}
37+
debug!(?opaque_types);
38+
39+
self.compute_concrete_opaque_types(&opaque_types);
40+
self.apply_computed_concrete_opaque_types(&opaque_types);
41+
}
42+
}
43+
44+
enum UsageKind<'tcx> {
45+
None,
46+
NonDefiningUse(OpaqueHiddenType<'tcx>),
47+
UnconstrainedHiddenType(OpaqueHiddenType<'tcx>),
48+
HasDefiningUse,
49+
}
50+
51+
impl<'tcx> UsageKind<'tcx> {
52+
fn merge(&mut self, other: UsageKind<'tcx>) {
53+
match (&*self, &other) {
54+
(UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(),
55+
(UsageKind::None, _) => *self = other,
56+
// When mergining non-defining uses, prefer earlier ones. This means
57+
// the error happens as early as possible.
58+
(
59+
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
60+
UsageKind::NonDefiningUse(..),
61+
) => {}
62+
// When merging unconstrained hidden types, we prefer later ones. This is
63+
// used as in most cases, the defining use is the final return statement
64+
// of our function, and other uses with defining arguments are likely not
65+
// intended to be defining.
66+
(
67+
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
68+
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse,
69+
) => *self = other,
70+
}
71+
}
72+
}
73+
74+
impl<'tcx> FnCtxt<'_, 'tcx> {
75+
fn compute_concrete_opaque_types(
76+
&mut self,
77+
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
78+
) {
79+
let tcx = self.tcx;
80+
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
81+
else {
82+
unreachable!();
83+
};
84+
85+
for def_id in defining_opaque_types_and_generators {
86+
match tcx.def_kind(def_id) {
87+
DefKind::OpaqueTy => {}
88+
DefKind::Closure => continue,
89+
_ => unreachable!("not opaque or generator: {def_id:?}"),
90+
}
91+
92+
let mut usage_kind = UsageKind::None;
93+
for &(opaque_type_key, hidden_type) in opaque_types {
94+
if opaque_type_key.def_id != def_id {
95+
continue;
96+
}
97+
98+
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
99+
if let UsageKind::HasDefiningUse = usage_kind {
100+
break;
101+
}
102+
}
103+
104+
let guar = match usage_kind {
105+
UsageKind::None => {
106+
if let Some(guar) = self.tainted_by_errors() {
107+
guar
108+
} else {
109+
self.tcx.dcx().emit_err(TaitForwardCompat2 {
110+
span: self
111+
.tcx
112+
.def_ident_span(self.body_id)
113+
.unwrap_or_else(|| self.tcx.def_span(self.body_id)),
114+
opaque_type_span: self.tcx.def_span(def_id),
115+
opaque_type: self.tcx.def_path_str(def_id),
116+
})
117+
}
118+
}
119+
UsageKind::NonDefiningUse(hidden_type) => {
120+
tcx.dcx().span_err(hidden_type.span, "non-defining use in the defining scope")
121+
}
122+
UsageKind::UnconstrainedHiddenType(hidden_type) => {
123+
let infer_var = hidden_type
124+
.ty
125+
.walk()
126+
.filter_map(ty::GenericArg::as_term)
127+
.find(|term| term.is_infer())
128+
.unwrap_or_else(|| hidden_type.ty.into());
129+
self.err_ctxt()
130+
.emit_inference_failure_err(
131+
self.body_id,
132+
hidden_type.span,
133+
infer_var,
134+
TypeAnnotationNeeded::E0282,
135+
false,
136+
)
137+
.emit()
138+
}
139+
UsageKind::HasDefiningUse => continue,
140+
};
141+
142+
self.typeck_results
143+
.borrow_mut()
144+
.concrete_opaque_types
145+
.insert(def_id, OpaqueHiddenType::new_error(tcx, guar));
146+
self.set_tainted_by_errors(guar);
147+
}
148+
}
149+
150+
fn consider_opaque_type_use(
151+
&mut self,
152+
opaque_type_key: OpaqueTypeKey<'tcx>,
153+
hidden_type: OpaqueHiddenType<'tcx>,
154+
) -> UsageKind<'tcx> {
155+
if let Err(err) = opaque_type_has_defining_use_args(
156+
&self,
157+
opaque_type_key,
158+
hidden_type.span,
159+
DefiningScopeKind::HirTypeck,
160+
) {
161+
match err {
162+
NonDefiningUseReason::Tainted(guar) => {
163+
self.typeck_results.borrow_mut().concrete_opaque_types.insert(
164+
opaque_type_key.def_id,
165+
OpaqueHiddenType::new_error(self.tcx, guar),
166+
);
167+
return UsageKind::HasDefiningUse;
168+
}
169+
_ => return UsageKind::NonDefiningUse(hidden_type),
170+
};
171+
}
172+
173+
// We ignore uses of the opaque if they have any inference variables
174+
// as this can frequently happen with recursive calls.
175+
//
176+
// See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
177+
if hidden_type.ty.has_non_region_infer() {
178+
return UsageKind::UnconstrainedHiddenType(hidden_type);
179+
}
180+
181+
let cause = ObligationCause::misc(hidden_type.span, self.body_id);
182+
let at = self.at(&cause, self.param_env);
183+
let hidden_type = match solve::deeply_normalize(at, hidden_type) {
184+
Ok(hidden_type) => hidden_type,
185+
Err(errors) => {
186+
let guar = self.err_ctxt().report_fulfillment_errors(errors);
187+
OpaqueHiddenType::new_error(self.tcx, guar)
188+
}
189+
};
190+
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
191+
opaque_type_key,
192+
self.tcx,
193+
DefiningScopeKind::HirTypeck,
194+
);
195+
196+
let prev = self
197+
.typeck_results
198+
.borrow_mut()
199+
.concrete_opaque_types
200+
.insert(opaque_type_key.def_id, hidden_type);
201+
assert!(prev.is_none());
202+
UsageKind::HasDefiningUse
203+
}
204+
205+
fn apply_computed_concrete_opaque_types(
206+
&mut self,
207+
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
208+
) {
209+
let tcx = self.tcx;
210+
for &(key, hidden_type) in opaque_types {
211+
let expected =
212+
*self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap();
213+
214+
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
215+
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
216+
}
217+
}
218+
3219
/// We may in theory add further uses of an opaque after cloning the opaque
4220
/// types storage during writeback when computing the defining uses.
5221
///

0 commit comments

Comments
 (0)