Skip to content

Commit e4c1a00

Browse files
Get rid of check_opaque_type_well_formed
1 parent b91a3a0 commit e4c1a00

25 files changed

+240
-405
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+1-89
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
use rustc_data_structures::fx::FxIndexMap;
22
use rustc_errors::ErrorGuaranteed;
3-
use rustc_hir::OpaqueTyOrigin;
4-
use rustc_hir::def::DefKind;
53
use rustc_hir::def_id::LocalDefId;
64
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
7-
use rustc_infer::traits::{Obligation, ObligationCause};
85
use rustc_macros::extension;
96
use rustc_middle::ty::visit::TypeVisitableExt;
107
use rustc_middle::ty::{
118
self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
129
TypingMode,
1310
};
1411
use rustc_span::Span;
15-
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
1612
use rustc_trait_selection::traits::ObligationCtxt;
1713
use tracing::{debug, instrument};
1814

@@ -303,91 +299,7 @@ impl<'tcx> InferCtxt<'tcx> {
303299
return Ty::new_error(self.tcx, e);
304300
}
305301

306-
// `definition_ty` does not live in of the current inference context,
307-
// so lets make sure that we don't accidentally misuse our current `infcx`.
308-
match check_opaque_type_well_formed(
309-
self.tcx,
310-
self.next_trait_solver(),
311-
opaque_type_key.def_id,
312-
instantiated_ty.span,
313-
definition_ty,
314-
) {
315-
Ok(hidden_ty) => hidden_ty,
316-
Err(guar) => Ty::new_error(self.tcx, guar),
317-
}
318-
}
319-
}
320-
321-
/// This logic duplicates most of `check_opaque_meets_bounds`.
322-
/// FIXME(oli-obk): Also do region checks here and then consider removing
323-
/// `check_opaque_meets_bounds` entirely.
324-
fn check_opaque_type_well_formed<'tcx>(
325-
tcx: TyCtxt<'tcx>,
326-
next_trait_solver: bool,
327-
def_id: LocalDefId,
328-
definition_span: Span,
329-
definition_ty: Ty<'tcx>,
330-
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
331-
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
332-
// on stable and we'd break that.
333-
let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id);
334-
let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else {
335-
return Ok(definition_ty);
336-
};
337-
let param_env = tcx.param_env(def_id);
338-
339-
let mut parent_def_id = def_id;
340-
while tcx.def_kind(parent_def_id) == DefKind::OpaqueTy {
341-
parent_def_id = tcx.local_parent(parent_def_id);
342-
}
343-
344-
// FIXME(#132279): This should eventually use the already defined hidden types
345-
// instead. Alternatively we'll entirely remove this function given we also check
346-
// the opaque in `check_opaque_meets_bounds` later.
347-
let infcx = tcx
348-
.infer_ctxt()
349-
.with_next_trait_solver(next_trait_solver)
350-
.build(TypingMode::analysis_in_body(tcx, parent_def_id));
351-
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
352-
let identity_args = GenericArgs::identity_for_item(tcx, def_id);
353-
354-
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
355-
// the bounds that the function supplies.
356-
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
357-
ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
358-
.map_err(|err| {
359-
infcx
360-
.err_ctxt()
361-
.report_mismatched_types(
362-
&ObligationCause::misc(definition_span, def_id),
363-
param_env,
364-
opaque_ty,
365-
definition_ty,
366-
err,
367-
)
368-
.emit()
369-
})?;
370-
371-
// Require the hidden type to be well-formed with only the generics of the opaque type.
372-
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
373-
// hidden type is well formed even without those bounds.
374-
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
375-
definition_ty.into(),
376-
)));
377-
ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
378-
379-
// Check that all obligations are satisfied by the implementation's
380-
// version.
381-
let errors = ocx.select_all_or_error();
382-
383-
// This is fishy, but we check it again in `check_opaque_meets_bounds`.
384-
// Remove once we can prepopulate with known hidden types.
385-
let _ = infcx.take_opaque_types();
386-
387-
if errors.is_empty() {
388-
Ok(definition_ty)
389-
} else {
390-
Err(infcx.err_ctxt().report_fulfillment_errors(errors))
302+
definition_ty
391303
}
392304
}
393305

compiler/rustc_hir_analysis/src/check/check.rs

+105-17
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use rustc_abi::FieldIdx;
55
use rustc_data_structures::unord::{UnordMap, UnordSet};
66
use rustc_errors::MultiSpan;
77
use rustc_errors::codes::*;
8-
use rustc_hir::Node;
98
use rustc_hir::def::{CtorKind, DefKind};
9+
use rustc_hir::{Node, intravisit};
1010
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
1111
use rustc_infer::traits::Obligation;
1212
use rustc_lint_defs::builtin::{
1313
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
1414
};
15+
use rustc_middle::hir::nested_filter;
1516
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
1617
use rustc_middle::middle::stability::EvalResult;
1718
use rustc_middle::span_bug;
@@ -190,7 +191,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
190191
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
191192
/// projections that would result in "inheriting lifetimes".
192193
fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
193-
let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id);
194+
let hir::OpaqueTy { origin, .. } = *tcx.hir().expect_opaque_ty(def_id);
194195

195196
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
196197
// `async-std` (and `pub async fn` in general).
@@ -200,23 +201,20 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
200201
return;
201202
}
202203

203-
let span = tcx.def_span(def_id);
204-
205204
if tcx.type_of(def_id).instantiate_identity().references_error() {
206205
return;
207206
}
208-
if check_opaque_for_cycles(tcx, def_id, span).is_err() {
207+
if check_opaque_for_cycles(tcx, def_id).is_err() {
209208
return;
210209
}
211210

212-
let _ = check_opaque_meets_bounds(tcx, def_id, span, origin);
211+
let _ = check_opaque_meets_bounds(tcx, def_id, origin);
213212
}
214213

215214
/// Checks that an opaque type does not contain cycles.
216215
pub(super) fn check_opaque_for_cycles<'tcx>(
217216
tcx: TyCtxt<'tcx>,
218217
def_id: LocalDefId,
219-
span: Span,
220218
) -> Result<(), ErrorGuaranteed> {
221219
let args = GenericArgs::identity_for_item(tcx, def_id);
222220

@@ -233,7 +231,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
233231
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
234232
.is_err()
235233
{
236-
let reported = opaque_type_cycle_error(tcx, def_id, span);
234+
let reported = opaque_type_cycle_error(tcx, def_id);
237235
return Err(reported);
238236
}
239237

@@ -267,10 +265,11 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
267265
fn check_opaque_meets_bounds<'tcx>(
268266
tcx: TyCtxt<'tcx>,
269267
def_id: LocalDefId,
270-
span: Span,
271-
origin: &hir::OpaqueTyOrigin<LocalDefId>,
268+
origin: hir::OpaqueTyOrigin<LocalDefId>,
272269
) -> Result<(), ErrorGuaranteed> {
273-
let defining_use_anchor = match *origin {
270+
let span = span_of_opaque(tcx, def_id, origin).unwrap_or_else(|| tcx.def_span(def_id));
271+
272+
let defining_use_anchor = match origin {
274273
hir::OpaqueTyOrigin::FnReturn { parent, .. }
275274
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
276275
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
@@ -281,7 +280,7 @@ fn check_opaque_meets_bounds<'tcx>(
281280
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor));
282281
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
283282

284-
let args = match *origin {
283+
let args = match origin {
285284
hir::OpaqueTyOrigin::FnReturn { parent, .. }
286285
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
287286
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
@@ -308,6 +307,7 @@ fn check_opaque_meets_bounds<'tcx>(
308307

309308
let misc_cause = traits::ObligationCause::misc(span, def_id);
310309

310+
// FIXME: We should just register the item bounds here, rather than equating.
311311
match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
312312
Ok(()) => {}
313313
Err(ty_err) => {
@@ -364,6 +364,97 @@ fn check_opaque_meets_bounds<'tcx>(
364364
}
365365
}
366366

367+
fn span_of_opaque<'tcx>(
368+
tcx: TyCtxt<'tcx>,
369+
opaque_def_id: LocalDefId,
370+
origin: hir::OpaqueTyOrigin<LocalDefId>,
371+
) -> Option<Span> {
372+
struct TaitConstraintLocator<'tcx> {
373+
opaque_def_id: LocalDefId,
374+
tcx: TyCtxt<'tcx>,
375+
}
376+
impl<'tcx> TaitConstraintLocator<'tcx> {
377+
fn check(&self, item_def_id: LocalDefId) -> ControlFlow<Span> {
378+
if !self.tcx.has_typeck_results(item_def_id) {
379+
return ControlFlow::Continue(());
380+
}
381+
382+
if let Some(hidden_ty) =
383+
self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
384+
{
385+
ControlFlow::Break(hidden_ty.span)
386+
} else {
387+
ControlFlow::Continue(())
388+
}
389+
}
390+
}
391+
impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
392+
type NestedFilter = nested_filter::All;
393+
type Result = ControlFlow<Span>;
394+
fn nested_visit_map(&mut self) -> Self::Map {
395+
self.tcx.hir()
396+
}
397+
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
398+
if let hir::ExprKind::Closure(closure) = ex.kind {
399+
self.check(closure.def_id)?;
400+
}
401+
intravisit::walk_expr(self, ex)
402+
}
403+
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result {
404+
self.check(it.owner_id.def_id)?;
405+
intravisit::walk_item(self, it)
406+
}
407+
fn visit_impl_item(&mut self, it: &'tcx hir::ImplItem<'tcx>) -> Self::Result {
408+
self.check(it.owner_id.def_id)?;
409+
intravisit::walk_impl_item(self, it)
410+
}
411+
fn visit_trait_item(&mut self, it: &'tcx hir::TraitItem<'tcx>) -> Self::Result {
412+
self.check(it.owner_id.def_id)?;
413+
intravisit::walk_trait_item(self, it)
414+
}
415+
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Result {
416+
intravisit::walk_foreign_item(self, it)
417+
}
418+
}
419+
420+
let mut locator = TaitConstraintLocator { tcx, opaque_def_id };
421+
match origin {
422+
hir::OpaqueTyOrigin::FnReturn { parent, .. }
423+
| hir::OpaqueTyOrigin::AsyncFn { parent, .. } => locator.check(parent).break_value(),
424+
hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty: true } => {
425+
let impl_def_id = tcx.local_parent(parent);
426+
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
427+
match assoc.kind {
428+
ty::AssocKind::Const | ty::AssocKind::Fn => {
429+
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
430+
{
431+
return Some(span);
432+
}
433+
}
434+
ty::AssocKind::Type => {}
435+
}
436+
}
437+
438+
None
439+
}
440+
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
441+
let scope = tcx.hir().get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
442+
let found = if scope == hir::CRATE_HIR_ID {
443+
tcx.hir().walk_toplevel_module(&mut locator)
444+
} else {
445+
match tcx.hir_node(scope) {
446+
Node::Item(it) => locator.visit_item(it),
447+
Node::ImplItem(it) => locator.visit_impl_item(it),
448+
Node::TraitItem(it) => locator.visit_trait_item(it),
449+
Node::ForeignItem(it) => locator.visit_foreign_item(it),
450+
other => bug!("{:?} is not a valid scope for an opaque type item", other),
451+
}
452+
};
453+
found.break_value()
454+
}
455+
}
456+
}
457+
367458
fn sanity_check_found_hidden_type<'tcx>(
368459
tcx: TyCtxt<'tcx>,
369460
key: ty::OpaqueTypeKey<'tcx>,
@@ -1535,11 +1626,8 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
15351626
///
15361627
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
15371628
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
1538-
fn opaque_type_cycle_error(
1539-
tcx: TyCtxt<'_>,
1540-
opaque_def_id: LocalDefId,
1541-
span: Span,
1542-
) -> ErrorGuaranteed {
1629+
fn opaque_type_cycle_error(tcx: TyCtxt<'_>, opaque_def_id: LocalDefId) -> ErrorGuaranteed {
1630+
let span = tcx.def_span(opaque_def_id);
15431631
let mut err = struct_span_code_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type");
15441632

15451633
let mut label = false;

tests/ui/async-await/issue-70935-complex-spans.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
1414

1515
fn foo(x: NotSync) -> impl Future + Send {
1616
//~^ ERROR `*mut ()` cannot be shared between threads safely
17-
//~| ERROR `*mut ()` cannot be shared between threads safely
1817
async move {
18+
//~^ ERROR `*mut ()` cannot be shared between threads safely
1919
baz(|| async {
2020
foo(x.clone());
2121
}).await;

tests/ui/async-await/issue-70935-complex-spans.stderr

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
error[E0277]: `*mut ()` cannot be shared between threads safely
2-
--> $DIR/issue-70935-complex-spans.rs:15:23
2+
--> $DIR/issue-70935-complex-spans.rs:17:5
33
|
4-
LL | fn foo(x: NotSync) -> impl Future + Send {
5-
| ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
4+
LL | / async move {
5+
LL | |
6+
LL | | baz(|| async {
7+
LL | | foo(x.clone());
8+
LL | | }).await;
9+
LL | | }
10+
| |_____^ `*mut ()` cannot be shared between threads safely
611
|
712
= help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`
813
note: required because it appears within the type `PhantomData<*mut ()>`
@@ -26,7 +31,7 @@ LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
2631
LL | | }
2732
| |_^
2833
note: required because it's used within this `async` block
29-
--> $DIR/issue-70935-complex-spans.rs:18:5
34+
--> $DIR/issue-70935-complex-spans.rs:17:5
3035
|
3136
LL | async move {
3237
| ^^^^^^^^^^
@@ -59,11 +64,10 @@ LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
5964
LL | | }
6065
| |_^
6166
note: required because it's used within this `async` block
62-
--> $DIR/issue-70935-complex-spans.rs:18:5
67+
--> $DIR/issue-70935-complex-spans.rs:17:5
6368
|
6469
LL | async move {
6570
| ^^^^^^^^^^
66-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
6771

6872
error: aborting due to 2 previous errors
6973

0 commit comments

Comments
 (0)