1
Fork 0

Auto merge of #138785 - lcnr:typing-mode-borrowck, r=compiler-errors,oli-obk

add `TypingMode::Borrowck`

Shares the first commit with #138499, doesn't really matter which PR to land first 😊 😁

Introduces `TypingMode::Borrowck` which unlike `TypingMode::Analysis`, uses the hidden type computed by HIR typeck as the initial value of opaques instead of an unconstrained infer var. This is a part of https://github.com/rust-lang/types-team/issues/129.

Using this new `TypingMode` is unfortunately a breaking change for now, see tests/ui/impl-trait/non-defining-uses/as-projection-term.rs. Using an inference variable as the initial value results in non-defining uses in the defining scope. We therefore only enable it if with `-Znext-solver=globally` or `-Ztyping-mode-borrowck`

To do that the PR contains the following changes:
- `TypeckResults::concrete_opaque_type` are already mapped to the definition of the opaque type
  - writeback now checks that the non-lifetime parameters of the opaque are universal
  - for this, `fn check_opaque_type_parameter_valid` is moved from `rustc_borrowck` to `rustc_trait_selection`
- we add a new `query type_of_opaque_hir_typeck` which, using the same visitors as MIR typeck, attempts to merge the hidden types from HIR typeck from all defining scopes
  - done by adding a `DefiningScopeKind` flag to toggle between using borrowck and HIR typeck
  - the visitors stop checking that the MIR type matches the HIR type. This is trivial as the HIR type are now used as the initial hidden types of the opaque. This check is useful as a safeguard when not using `TypingMode::Borrowck`, but adding it to the new structure is annoying and it's not soundness critical, so I intend to not add it back.
- add a `TypingMode::Borrowck`  which behaves just like `TypingMode::Analysis` except when normalizing opaque types
   - it uses `type_of_opaque_hir_typeck(opaque)` as the initial value after replacing its regions with new inference vars
   - it uses structural lookup in the new solver

fixes #112201, fixes #132335, fixes #137751

r? `@compiler-errors` `@oli-obk`
This commit is contained in:
bors 2025-04-04 19:54:42 +00:00
commit 17ffbc81a3
136 changed files with 1069 additions and 993 deletions

View file

@ -162,13 +162,6 @@ borrowck_opaque_type_lifetime_mismatch =
.prev_lifetime_label = lifetime `{$prev}` previously used here .prev_lifetime_label = lifetime `{$prev}` previously used here
.note = if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types .note = if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
borrowck_opaque_type_non_generic_param =
expected generic {$kind} parameter, found `{$ty}`
.label = {STREQ($ty, "'static") ->
[true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
*[other] this generic parameter must be used with a generic {$kind} parameter
}
borrowck_partial_var_move_by_use_in_closure = borrowck_partial_var_move_by_use_in_closure =
variable {$is_partial -> variable {$is_partial ->
[true] partially moved [true] partially moved

View file

@ -35,7 +35,7 @@ use rustc_infer::infer::{
}; };
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode, fold_regions}; use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::impls::{ use rustc_mir_dataflow::impls::{
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
@ -171,12 +171,6 @@ fn do_mir_borrowck<'tcx>(
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted); let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
let body = &body_owned; // no further changes 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 = PoloniusLocationTable::new(body); let location_table = PoloniusLocationTable::new(body);
let move_data = MoveData::gather_moves(body, tcx, |_| true); let move_data = MoveData::gather_moves(body, tcx, |_| true);
@ -431,7 +425,12 @@ pub(crate) struct BorrowckInferCtxt<'tcx> {
impl<'tcx> BorrowckInferCtxt<'tcx> { impl<'tcx> BorrowckInferCtxt<'tcx> {
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id)); let typing_mode = if tcx.use_typing_mode_borrowck() {
TypingMode::borrowck(tcx, def_id)
} else {
TypingMode::analysis_in_body(tcx, def_id)
};
let infcx = tcx.infer_ctxt().build(typing_mode);
let param_env = tcx.param_env(def_id); let param_env = tcx.param_env(def_id);
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env } BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
} }
@ -478,29 +477,6 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
next_region 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) = fold_regions(tcx, data, |_, _| {
self.next_nll_region_var_in_universe(
NllRegionVariableOrigin::Existential { from_forall: false },
ty::UniverseIndex::ROOT,
)
});
let prev = self.register_hidden_type_in_storage(key, hidden_ty);
assert_eq!(prev, None);
}
}
} }
impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {

View file

@ -1,22 +1,17 @@
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_hir::OpaqueTyOrigin;
use rustc_hir::def_id::LocalDefId;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, self, DefiningScopeKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, TypingMode, fold_regions, TypeVisitableExt, fold_regions,
}; };
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt; use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use super::RegionInferenceContext; use super::RegionInferenceContext;
use crate::opaque_types::ConcreteOpaqueTypes; use crate::opaque_types::ConcreteOpaqueTypes;
use crate::session_diagnostics::{LifetimeMismatchOpaqueParam, NonGenericOpaqueTypeParam}; use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
use crate::universal_regions::RegionClassification; use crate::universal_regions::RegionClassification;
impl<'tcx> RegionInferenceContext<'tcx> { impl<'tcx> RegionInferenceContext<'tcx> {
@ -272,14 +267,21 @@ impl<'tcx> InferCtxt<'tcx> {
return Ty::new_error(self.tcx, e); return Ty::new_error(self.tcx, e);
} }
if let Err(guar) = if let Err(guar) = check_opaque_type_parameter_valid(
check_opaque_type_parameter_valid(self, opaque_type_key, instantiated_ty.span) self,
{ opaque_type_key,
instantiated_ty.span,
DefiningScopeKind::MirBorrowck,
) {
return Ty::new_error(self.tcx, guar); return Ty::new_error(self.tcx, guar);
} }
let definition_ty = instantiated_ty let definition_ty = instantiated_ty
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .remap_generic_params_to_declaration_params(
opaque_type_key,
self.tcx,
DefiningScopeKind::MirBorrowck,
)
.ty; .ty;
if let Err(e) = definition_ty.error_reported() { if let Err(e) = definition_ty.error_reported() {
@ -289,156 +291,3 @@ impl<'tcx> InferCtxt<'tcx> {
definition_ty definition_ty
} }
} }
/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter].
///
/// [rustc-dev-guide chapter]:
/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
fn check_opaque_type_parameter_valid<'tcx>(
infcx: &InferCtxt<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let tcx = infcx.tcx;
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) => {
matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
|| (lt.is_static() && opaque_env.param_equal_static(i))
}
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
};
if arg_is_param {
// Register if the same lifetime appears multiple times in the generic args.
// There is an exception when the opaque type *requires* the lifetimes to be equal.
// See [rustc-dev-guide chapter] § "An exception to uniqueness rule".
let seen_where = seen_params.entry(arg).or_default();
if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) {
seen_where.push(i);
}
} else {
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = opaque_generics.param_at(i, tcx);
let kind = opaque_param.kind.descr();
opaque_env.param_is_error(i)?;
return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
ty: arg,
kind,
span,
param_span: tcx.def_span(opaque_param.def_id),
}));
}
}
for (_, indices) in seen_params {
if indices.len() > 1 {
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
let spans: Vec<_> = indices
.into_iter()
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
.collect();
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
return Err(infcx
.dcx()
.struct_span_err(span, "non-defining opaque type use in defining scope")
.with_span_note(spans, format!("{descr} used multiple times"))
.emit());
}
}
Ok(())
}
/// Computes if an opaque type requires a lifetime parameter to be equal to
/// another one or to the `'static` lifetime.
/// These requirements are derived from the explicit and implied bounds.
struct LazyOpaqueTyEnv<'tcx> {
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
/// Equal parameters will have the same name. Computed Lazily.
/// Example:
/// `type Opaque<'a: 'static, 'b: 'c, 'c: 'b> = impl Sized;`
/// Identity args: `['a, 'b, 'c]`
/// Canonical args: `['static, 'b, 'b]`
canonical_args: std::cell::OnceCell<ty::GenericArgsRef<'tcx>>,
}
impl<'tcx> LazyOpaqueTyEnv<'tcx> {
fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() }
}
fn param_equal_static(&self, param_index: usize) -> bool {
self.get_canonical_args()[param_index].expect_region().is_static()
}
fn params_equal(&self, param1: usize, param2: usize) -> bool {
let canonical_args = self.get_canonical_args();
canonical_args[param1] == canonical_args[param2]
}
fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> {
self.get_canonical_args()[param_index].error_reported()
}
fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
if let Some(&canonical_args) = self.canonical_args.get() {
return canonical_args;
}
let &Self { tcx, def_id, .. } = self;
let origin = tcx.local_opaque_ty_origin(def_id);
let parent = match origin {
OpaqueTyOrigin::FnReturn { parent, .. }
| OpaqueTyOrigin::AsyncFn { parent, .. }
| OpaqueTyOrigin::TyAlias { parent, .. } => parent,
};
let param_env = tcx.param_env(parent);
let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
tcx,
def_id.to_def_id(),
|param, _| {
tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
},
);
// FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're
// in a body here.
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new(&infcx);
let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
Default::default()
});
let outlives_env = OutlivesEnvironment::new(&infcx, parent, param_env, wf_tys);
let mut seen = vec![tcx.lifetimes.re_static];
let canonical_args = fold_regions(tcx, args, |r1, _| {
if r1.is_error() {
r1
} else if let Some(&r2) = seen.iter().find(|&&r2| {
let free_regions = outlives_env.free_region_map();
free_regions.sub_free_regions(tcx, r1, r2)
&& free_regions.sub_free_regions(tcx, r2, r1)
}) {
r2
} else {
seen.push(r1);
r1
}
});
self.canonical_args.set(canonical_args).unwrap();
canonical_args
}
}

View file

@ -294,17 +294,6 @@ pub(crate) struct MoveBorrow<'a> {
pub borrow_span: Span, pub borrow_span: Span,
} }
#[derive(Diagnostic)]
#[diag(borrowck_opaque_type_non_generic_param, code = E0792)]
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
pub ty: GenericArg<'tcx>,
pub kind: &'a str,
#[primary_span]
pub span: Span,
#[label]
pub param_span: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(borrowck_opaque_type_lifetime_mismatch)] #[diag(borrowck_opaque_type_lifetime_mismatch)]
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> { pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {

View file

@ -61,6 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { *providers = Providers {
type_of: type_of::type_of, type_of: type_of::type_of,
type_of_opaque: type_of::type_of_opaque, type_of_opaque: type_of::type_of_opaque,
type_of_opaque_hir_typeck: type_of::type_of_opaque_hir_typeck,
type_alias_is_lazy: type_of::type_alias_is_lazy, type_alias_is_lazy: type_of::type_alias_is_lazy,
item_bounds: item_bounds::item_bounds, item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds,

View file

@ -7,7 +7,9 @@ use rustc_hir::{self as hir, AmbigArg, HirId};
use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, fold_regions}; use rustc_middle::ty::{
self, DefiningScopeKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, fold_regions,
};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Ident, Span}; use rustc_span::{DUMMY_SP, Ident, Span};
@ -324,10 +326,18 @@ pub(super) fn type_of_opaque(
if let Some(def_id) = def_id.as_local() { if let Some(def_id) = def_id.as_local() {
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => { hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
opaque::find_opaque_ty_constraints_for_tait(tcx, def_id) opaque::find_opaque_ty_constraints_for_tait(
tcx,
def_id,
DefiningScopeKind::MirBorrowck,
)
} }
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => { hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id) opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
tcx,
def_id,
DefiningScopeKind::MirBorrowck,
)
} }
// Opaque types desugared from `impl Trait`. // Opaque types desugared from `impl Trait`.
hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl } hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
@ -340,7 +350,12 @@ pub(super) fn type_of_opaque(
"tried to get type of this RPITIT with no definition" "tried to get type of this RPITIT with no definition"
); );
} }
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) opaque::find_opaque_ty_constraints_for_rpit(
tcx,
def_id,
owner,
DefiningScopeKind::MirBorrowck,
)
} }
})) }))
} else { } else {
@ -350,6 +365,42 @@ pub(super) fn type_of_opaque(
} }
} }
pub(super) fn type_of_opaque_hir_typeck(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> ty::EarlyBinder<'_, Ty<'_>> {
ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
opaque::find_opaque_ty_constraints_for_tait(tcx, def_id, DefiningScopeKind::HirTypeck)
}
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
tcx,
def_id,
DefiningScopeKind::HirTypeck,
)
}
// Opaque types desugared from `impl Trait`.
hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
| hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => {
if in_trait_or_impl == Some(hir::RpitContext::Trait)
&& !tcx.defaultness(owner).has_value()
{
span_bug!(
tcx.def_span(def_id),
"tried to get type of this RPITIT with no definition"
);
}
opaque::find_opaque_ty_constraints_for_rpit(
tcx,
def_id,
owner,
DefiningScopeKind::HirTypeck,
)
}
})
}
fn infer_placeholder_type<'tcx>( fn infer_placeholder_type<'tcx>(
cx: &dyn HirTyLowerer<'tcx>, cx: &dyn HirTyLowerer<'tcx>,
def_id: LocalDefId, def_id: LocalDefId,

View file

@ -3,8 +3,7 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit}; use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, DefiningScopeKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use tracing::{debug, instrument, trace}; use tracing::{debug, instrument, trace};
use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType}; use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
@ -15,6 +14,7 @@ use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
def_id: LocalDefId, def_id: LocalDefId,
opaque_types_from: DefiningScopeKind,
) -> Ty<'_> { ) -> Ty<'_> {
let mut parent_def_id = def_id; let mut parent_def_id = def_id;
while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy { while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
@ -27,7 +27,7 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
other => bug!("invalid impl trait in assoc type parent: {other:?}"), other => bug!("invalid impl trait in assoc type parent: {other:?}"),
} }
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] }; let mut locator = TaitConstraintLocator { def_id, tcx, found: None, opaque_types_from };
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) { for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
let assoc = tcx.associated_item(assoc_id); let assoc = tcx.associated_item(assoc_id);
@ -39,25 +39,14 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
} }
if let Some(hidden) = locator.found { if let Some(hidden) = locator.found {
// Only check against typeck if we didn't already error
if !hidden.ty.references_error() {
for concrete_type in locator.typeck_types {
if concrete_type.ty != tcx.erase_regions(hidden.ty) {
if let Ok(d) = hidden.build_mismatch_error(&concrete_type, tcx) {
d.emit();
}
}
}
}
hidden.ty hidden.ty
} else { } else {
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType { let guar = tcx.dcx().emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id), span: tcx.def_span(def_id),
name: tcx.item_ident(parent_def_id.to_def_id()), name: tcx.item_ident(parent_def_id.to_def_id()),
what: "impl", what: "impl",
}); });
Ty::new_error(tcx, reported) Ty::new_error(tcx, guar)
} }
} }
@ -80,23 +69,16 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
/// fn b<T>() -> Foo<T, u32> { .. } /// fn b<T>() -> Foo<T, u32> { .. }
/// ``` /// ```
#[instrument(skip(tcx), level = "debug")] #[instrument(skip(tcx), level = "debug")]
pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { pub(super) fn find_opaque_ty_constraints_for_tait(
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] }; tcx: TyCtxt<'_>,
def_id: LocalDefId,
opaque_types_from: DefiningScopeKind,
) -> Ty<'_> {
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, opaque_types_from };
tcx.hir_walk_toplevel_module(&mut locator); tcx.hir_walk_toplevel_module(&mut locator);
if let Some(hidden) = locator.found { if let Some(hidden) = locator.found {
// Only check against typeck if we didn't already error
if !hidden.ty.references_error() {
for concrete_type in locator.typeck_types {
if concrete_type.ty != tcx.erase_regions(hidden.ty) {
if let Ok(d) = hidden.build_mismatch_error(&concrete_type, tcx) {
d.emit();
}
}
}
}
hidden.ty hidden.ty
} else { } else {
let mut parent_def_id = def_id; let mut parent_def_id = def_id;
@ -104,12 +86,12 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
// Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031) // Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
parent_def_id = tcx.local_parent(parent_def_id); parent_def_id = tcx.local_parent(parent_def_id);
} }
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType { let guar = tcx.dcx().emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id), span: tcx.def_span(def_id),
name: tcx.item_ident(parent_def_id.to_def_id()), name: tcx.item_ident(parent_def_id.to_def_id()),
what: "crate", what: "crate",
}); });
Ty::new_error(tcx, reported) Ty::new_error(tcx, guar)
} }
} }
@ -126,22 +108,44 @@ struct TaitConstraintLocator<'tcx> {
/// type). /// type).
found: Option<ty::OpaqueHiddenType<'tcx>>, found: Option<ty::OpaqueHiddenType<'tcx>>,
/// In the presence of dead code, typeck may figure out a hidden type opaque_types_from: DefiningScopeKind,
/// while borrowck will not. We collect these cases here and check at }
/// the end that we actually found a type that matches (modulo regions).
typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>, impl<'tcx> TaitConstraintLocator<'tcx> {
fn insert_found(&mut self, hidden_ty: ty::OpaqueHiddenType<'tcx>) {
if let Some(prev) = &mut self.found {
if hidden_ty.ty != prev.ty {
let (Ok(guar) | Err(guar)) =
prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit());
prev.ty = Ty::new_error(self.tcx, guar);
}
} else {
self.found = Some(hidden_ty);
}
}
fn non_defining_use_in_defining_scope(&mut self, item_def_id: LocalDefId) {
let guar = self.tcx.dcx().emit_err(TaitForwardCompat2 {
span: self
.tcx
.def_ident_span(item_def_id)
.unwrap_or_else(|| self.tcx.def_span(item_def_id)),
opaque_type_span: self.tcx.def_span(self.def_id),
opaque_type: self.tcx.def_path_str(self.def_id),
});
self.insert_found(ty::OpaqueHiddenType::new_error(self.tcx, guar));
} }
impl TaitConstraintLocator<'_> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn check(&mut self, item_def_id: LocalDefId) { fn check(&mut self, item_def_id: LocalDefId) {
// Don't try to check items that cannot possibly constrain the type. // Don't try to check items that cannot possibly constrain the type.
if !self.tcx.has_typeck_results(item_def_id) { let tcx = self.tcx;
if !tcx.has_typeck_results(item_def_id) {
debug!("no constraint: no typeck results"); debug!("no constraint: no typeck results");
return; return;
} }
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id); let opaque_types_defined_by = tcx.opaque_types_defined_by(item_def_id);
// Don't try to check items that cannot possibly constrain the type. // Don't try to check items that cannot possibly constrain the type.
if !opaque_types_defined_by.contains(&self.def_id) { if !opaque_types_defined_by.contains(&self.def_id) {
debug!("no constraint: no opaque types defined"); debug!("no constraint: no opaque types defined");
@ -152,7 +156,7 @@ impl TaitConstraintLocator<'_> {
// "non-defining use" errors for them. // "non-defining use" errors for them.
// Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
// excludes closures, which are allowed to have `_` in their return type. // excludes closures, which are allowed to have `_` in their return type.
let hir_node = self.tcx.hir_node_by_def_id(item_def_id); let hir_node = tcx.hir_node_by_def_id(item_def_id);
debug_assert!( debug_assert!(
!matches!(hir_node, Node::ForeignItem(..)), !matches!(hir_node, Node::ForeignItem(..)),
"foreign items cannot constrain opaque types", "foreign items cannot constrain opaque types",
@ -164,88 +168,39 @@ impl TaitConstraintLocator<'_> {
hir_sig.decl.output.span(), hir_sig.decl.output.span(),
"inferring return types and opaque types do not mix well", "inferring return types and opaque types do not mix well",
); );
self.found = self.found = Some(ty::OpaqueHiddenType::new_error(tcx, guar));
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
return; return;
} }
// Calling `mir_borrowck` can lead to cycle errors through match self.opaque_types_from {
// const-checking, avoid calling it if we don't have to. DefiningScopeKind::HirTypeck => {
// ```rust let tables = tcx.typeck(item_def_id);
// type Foo = impl Fn() -> usize; // when computing type for this
// const fn bar() -> Foo {
// || 0usize
// }
// const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
// // because we again need to reveal `Foo` so we can check whether the
// // constant does not contain interior mutability.
// ```
let tables = self.tcx.typeck(item_def_id);
if let Some(guar) = tables.tainted_by_errors { if let Some(guar) = tables.tainted_by_errors {
self.found = self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) }); } else if let Some(&hidden_type) = tables.concrete_opaque_types.get(&self.def_id) {
return; self.insert_found(hidden_type);
}
let mut constrained = false;
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
if opaque_type_key.def_id != self.def_id {
continue;
}
constrained = true;
let concrete_type =
self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
opaque_type_key,
self.tcx,
true,
));
if self.typeck_types.iter().all(|prev| prev.ty != concrete_type.ty) {
self.typeck_types.push(concrete_type);
}
}
if !constrained {
debug!("no constraints in typeck results");
if opaque_types_defined_by.contains(&self.def_id) {
let guar = self.tcx.dcx().emit_err(TaitForwardCompat2 {
span: self
.tcx
.def_ident_span(item_def_id)
.unwrap_or_else(|| self.tcx.def_span(item_def_id)),
opaque_type_span: self.tcx.def_span(self.def_id),
opaque_type: self.tcx.def_path_str(self.def_id),
});
// Avoid "opaque type not constrained" errors on the opaque itself.
self.found = Some(ty::OpaqueHiddenType {
span: DUMMY_SP,
ty: Ty::new_error(self.tcx, guar),
});
}
return;
};
// Use borrowck to get the type with unerased regions.
let borrowck_results = &self.tcx.mir_borrowck(item_def_id);
// If the body was tainted, then assume the opaque may have been constrained and just set it to error.
if let Some(guar) = borrowck_results.tainted_by_errors {
self.found =
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
return;
}
debug!(?borrowck_results.concrete_opaque_types);
if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) {
debug!(?concrete_type, "found constraint");
if let Some(prev) = &mut self.found {
if concrete_type.ty != prev.ty {
let (Ok(guar) | Err(guar)) =
prev.build_mismatch_error(&concrete_type, self.tcx).map(|d| d.emit());
prev.ty = Ty::new_error(self.tcx, guar);
}
} else { } else {
self.found = Some(concrete_type); self.non_defining_use_in_defining_scope(item_def_id);
}
}
DefiningScopeKind::MirBorrowck => {
let borrowck_result = tcx.mir_borrowck(item_def_id);
if let Some(guar) = borrowck_result.tainted_by_errors {
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
} else if let Some(&hidden_type) =
borrowck_result.concrete_opaque_types.get(&self.def_id)
{
debug!(?hidden_type, "found constraint");
self.insert_found(hidden_type);
} else if let Err(guar) = tcx
.type_of_opaque_hir_typeck(self.def_id)
.instantiate_identity()
.error_reported()
{
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
} else {
self.non_defining_use_in_defining_scope(item_def_id);
}
} }
} }
} }
@ -287,61 +242,19 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId, def_id: LocalDefId,
owner_def_id: LocalDefId, owner_def_id: LocalDefId,
opaque_types_from: DefiningScopeKind,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
match opaque_types_from {
DefiningScopeKind::HirTypeck => {
let tables = tcx.typeck(owner_def_id); let tables = tcx.typeck(owner_def_id);
if let Some(guar) = tables.tainted_by_errors {
// Check that all of the opaques we inferred during HIR are compatible.
// FIXME: We explicitly don't check that the types inferred during HIR
// typeck are compatible with the one that we infer during borrowck,
// because that one actually sometimes has consts evaluated eagerly so
// using strict type equality will fail.
let mut hir_opaque_ty: Option<ty::OpaqueHiddenType<'tcx>> = None;
if tables.tainted_by_errors.is_none() {
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
if opaque_type_key.def_id != def_id {
continue;
}
let concrete_type = tcx.erase_regions(
hidden_type.remap_generic_params_to_declaration_params(opaque_type_key, tcx, true),
);
if let Some(prev) = &mut hir_opaque_ty {
if concrete_type.ty != prev.ty {
if let Ok(d) = prev.build_mismatch_error(&concrete_type, tcx) {
d.emit();
}
}
} else {
hir_opaque_ty = Some(concrete_type);
}
}
}
let mir_opaque_ty = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied();
if let Some(mir_opaque_ty) = mir_opaque_ty {
if mir_opaque_ty.references_error() {
return mir_opaque_ty.ty;
}
debug!(?owner_def_id);
let mut locator = RpitConstraintChecker { def_id, tcx, found: mir_opaque_ty };
match tcx.hir_node_by_def_id(owner_def_id) {
Node::Item(it) => intravisit::walk_item(&mut locator, it),
Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
other => bug!("{:?} is not a valid scope for an opaque type item", other),
}
mir_opaque_ty.ty
} else if let Some(guar) = tables.tainted_by_errors {
// Some error in the owner fn prevented us from populating
// the `concrete_opaque_types` table.
Ty::new_error(tcx, guar) Ty::new_error(tcx, guar)
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
hidden_ty.ty
} else { } else {
// Fall back to the RPIT we inferred during HIR typeck // FIXME(-Znext-solver): This should not be necessary and we should
if let Some(hir_opaque_ty) = hir_opaque_ty { // instead rely on inference variable fallback inside of typeck itself.
hir_opaque_ty.ty
} else {
// We failed to resolve the opaque type or it // We failed to resolve the opaque type or it
// resolves to itself. We interpret this as the // resolves to itself. We interpret this as the
// no values of the hidden type ever being constructed, // no values of the hidden type ever being constructed,
@ -351,62 +264,20 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
Ty::new_diverging_default(tcx) Ty::new_diverging_default(tcx)
} }
} }
} DefiningScopeKind::MirBorrowck => {
let borrowck_result = tcx.mir_borrowck(owner_def_id);
struct RpitConstraintChecker<'tcx> { if let Some(guar) = borrowck_result.tainted_by_errors {
tcx: TyCtxt<'tcx>, Ty::new_error(tcx, guar)
} else if let Some(hidden_ty) = borrowck_result.concrete_opaque_types.get(&def_id) {
/// def_id of the opaque type whose defining uses are being checked hidden_ty.ty
def_id: LocalDefId, } else {
let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
found: ty::OpaqueHiddenType<'tcx>, if let Err(guar) = hir_ty.error_reported() {
} Ty::new_error(tcx, guar)
} else {
impl RpitConstraintChecker<'_> { hir_ty
#[instrument(skip(self), level = "debug")]
fn check(&self, def_id: LocalDefId) {
// Use borrowck to get the type with unerased regions.
let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
debug!(?concrete_opaque_types);
if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
debug!(?concrete_type, "found constraint");
if concrete_type.ty != self.found.ty {
if let Ok(d) = self.found.build_mismatch_error(&concrete_type, self.tcx) {
d.emit();
} }
} }
} }
} }
} }
impl<'tcx> intravisit::Visitor<'tcx> for RpitConstraintChecker<'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
self.tcx
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id);
intravisit::walk_item(self, it);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
trace!(?it.owner_id);
self.check(it.owner_id.def_id);
intravisit::walk_trait_item(self, it);
}
}

View file

@ -12,10 +12,12 @@ use rustc_middle::span_bug;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, fold_regions, self, DefiningScopeKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt, fold_regions,
}; };
use rustc_span::{Span, sym}; use rustc_span::{Span, sym};
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
use rustc_trait_selection::solve; use rustc_trait_selection::solve;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
@ -555,6 +557,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn visit_opaque_types(&mut self) { fn visit_opaque_types(&mut self) {
let tcx = self.tcx();
// We clone the opaques instead of stealing them here as they are still used for // We clone the opaques instead of stealing them here as they are still used for
// normalization in the next generation trait solver. // normalization in the next generation trait solver.
// //
@ -577,16 +580,46 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
} }
} }
// Here we only detect impl trait definition conflicts when they if let Err(guar) = check_opaque_type_parameter_valid(
// are equal modulo regions. &self.fcx,
if let Some(last_opaque_ty) = opaque_type_key,
self.typeck_results.concrete_opaque_types.insert(opaque_type_key, hidden_type) hidden_type.span,
&& last_opaque_ty.ty != hidden_type.ty DefiningScopeKind::HirTypeck,
{ ) {
assert!(!self.fcx.next_trait_solver()); self.typeck_results
if let Ok(d) = hidden_type.build_mismatch_error(&last_opaque_ty, self.tcx()) { .concrete_opaque_types
d.emit(); .insert(opaque_type_key.def_id, ty::OpaqueHiddenType::new_error(tcx, guar));
} }
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
opaque_type_key,
tcx,
DefiningScopeKind::HirTypeck,
);
if let Some(prev) = self
.typeck_results
.concrete_opaque_types
.insert(opaque_type_key.def_id, hidden_type)
{
let entry = &mut self
.typeck_results
.concrete_opaque_types
.get_mut(&opaque_type_key.def_id)
.unwrap();
if prev.ty != hidden_type.ty {
if let Some(guar) = self.typeck_results.tainted_by_errors {
entry.ty = Ty::new_error(tcx, guar);
} else {
let (Ok(guar) | Err(guar)) =
prev.build_mismatch_error(&hidden_type, tcx).map(|d| d.emit());
entry.ty = Ty::new_error(tcx, guar);
}
}
// Pick a better span if there is one.
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
entry.span = prev.span.substitute_dummy(hidden_type.span);
} }
} }
} }

View file

@ -967,7 +967,8 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool { pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
debug_assert!(!self.next_trait_solver()); debug_assert!(!self.next_trait_solver());
match self.typing_mode() { match self.typing_mode() {
TypingMode::Analysis { defining_opaque_types } => { TypingMode::Analysis { defining_opaque_types }
| TypingMode::Borrowck { defining_opaque_types } => {
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
} }
// FIXME(#132279): This function is quite weird in post-analysis // FIXME(#132279): This function is quite weird in post-analysis
@ -1261,7 +1262,8 @@ impl<'tcx> InferCtxt<'tcx> {
// to handle them without proper canonicalization. This means we may cause cycle // to handle them without proper canonicalization. This means we may cause cycle
// errors and fail to reveal opaques while inside of bodies. We should rename this // errors and fail to reveal opaques while inside of bodies. We should rename this
// function and require explicit comments on all use-sites in the future. // function and require explicit comments on all use-sites in the future.
ty::TypingMode::Analysis { defining_opaque_types: _ } => { ty::TypingMode::Analysis { defining_opaque_types: _ }
| ty::TypingMode::Borrowck { defining_opaque_types: _ } => {
TypingMode::non_body_analysis() TypingMode::non_body_analysis()
} }
mode @ (ty::TypingMode::Coherence mode @ (ty::TypingMode::Coherence

View file

@ -12,7 +12,7 @@ use rustc_middle::ty::{
use rustc_span::Span; use rustc_span::Span;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use super::DefineOpaqueTypes; use super::{DefineOpaqueTypes, RegionVariableOrigin};
use crate::errors::OpaqueHiddenTypeDiag; use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{InferCtxt, InferOk}; use crate::infer::{InferCtxt, InferOk};
use crate::traits::{self, Obligation, PredicateObligations}; use crate::traits::{self, Obligation, PredicateObligations};
@ -221,6 +221,7 @@ impl<'tcx> InferCtxt<'tcx> {
hidden_ty: Ty<'tcx>, hidden_ty: Ty<'tcx>,
goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>, goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
) -> Result<(), TypeError<'tcx>> { ) -> Result<(), TypeError<'tcx>> {
let tcx = self.tcx;
// Ideally, we'd get the span where *this specific `ty` came // Ideally, we'd get the span where *this specific `ty` came
// from*, but right now we just use the span from the overall // from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`, // value being folded. In simple cases like `-> impl Foo`,
@ -231,7 +232,7 @@ impl<'tcx> InferCtxt<'tcx> {
// During intercrate we do not define opaque types but instead always // During intercrate we do not define opaque types but instead always
// force ambiguity unless the hidden type is known to not implement // force ambiguity unless the hidden type is known to not implement
// our trait. // our trait.
goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous)); goals.push(Goal::new(tcx, param_env, ty::PredicateKind::Ambiguous));
} }
ty::TypingMode::Analysis { .. } => { ty::TypingMode::Analysis { .. } => {
let prev = self let prev = self
@ -249,6 +250,36 @@ impl<'tcx> InferCtxt<'tcx> {
); );
} }
} }
ty::TypingMode::Borrowck { .. } => {
let prev = self
.inner
.borrow_mut()
.opaque_types()
.register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
// We either equate the new hidden type with the previous entry or with the type
// inferred by HIR typeck.
let actual = prev.unwrap_or_else(|| {
let actual = tcx
.type_of_opaque_hir_typeck(opaque_type_key.def_id)
.instantiate(self.tcx, opaque_type_key.args);
let actual = ty::fold_regions(tcx, actual, |re, _dbi| match re.kind() {
ty::ReErased => {
self.next_region_var(RegionVariableOrigin::MiscVariable(span))
}
_ => re,
});
actual
});
goals.extend(
self.at(&ObligationCause::dummy_with_span(span), param_env)
.eq(DefineOpaqueTypes::Yes, hidden_ty, actual)?
.obligations
.into_iter()
.map(|obligation| obligation.as_goal()),
);
}
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => { mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
bug!("insert hidden type in {mode:?}") bug!("insert hidden type in {mode:?}")
} }

View file

@ -267,6 +267,8 @@ rustc_queries! {
/// ///
/// This is a specialized instance of [`Self::type_of`] that detects query cycles. /// This is a specialized instance of [`Self::type_of`] that detects query cycles.
/// Unless `CyclePlaceholder` needs to be handled separately, call [`Self::type_of`] instead. /// Unless `CyclePlaceholder` needs to be handled separately, call [`Self::type_of`] instead.
/// This is used to improve the error message in cases where revealing the hidden type
/// for auto-trait leakage cycles.
/// ///
/// # Panics /// # Panics
/// ///
@ -278,6 +280,12 @@ rustc_queries! {
} }
cycle_stash cycle_stash
} }
query type_of_opaque_hir_typeck(key: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
desc { |tcx|
"computing type of opaque `{path}` via HIR typeck",
path = tcx.def_path_str(key),
}
}
/// Returns whether the type alias given by `DefId` is lazy. /// Returns whether the type alias given by `DefId` is lazy.
/// ///

View file

@ -206,6 +206,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
self.type_of(def_id) self.type_of(def_id)
} }
fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
self.type_of_opaque_hir_typeck(def_id)
}
type AdtDef = ty::AdtDef<'tcx>; type AdtDef = ty::AdtDef<'tcx>;
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef { fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
@ -3271,6 +3274,11 @@ impl<'tcx> TyCtxt<'tcx> {
self.sess.opts.unstable_opts.next_solver.coherence self.sess.opts.unstable_opts.next_solver.coherence
} }
#[allow(rustc::bad_opt_access)]
pub fn use_typing_mode_borrowck(self) -> bool {
self.next_trait_solver_globally() || self.sess.opts.unstable_opts.typing_mode_borrowck
}
pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool { pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
self.opt_rpitit_info(def_id).is_some() self.opt_rpitit_info(def_id).is_some()
} }

View file

@ -48,7 +48,7 @@ use rustc_serialize::{Decodable, Encodable};
use rustc_session::lint::LintBuffer; use rustc_session::lint::LintBuffer;
pub use rustc_session::lint::RegisteredTools; pub use rustc_session::lint::RegisteredTools;
use rustc_span::hygiene::MacroKind; use rustc_span::hygiene::MacroKind;
use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym};
pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::relate::VarianceDiagInfo;
pub use rustc_type_ir::*; pub use rustc_type_ir::*;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
@ -782,7 +782,22 @@ pub struct OpaqueHiddenType<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
} }
/// Whether we're currently in HIR typeck or MIR borrowck.
#[derive(Debug, Clone, Copy)]
pub enum DefiningScopeKind {
/// During writeback in typeck, we don't care about regions and simply
/// erase them. This means we also don't check whether regions are
/// universal in the opaque type key. This will only be checked in
/// MIR borrowck.
HirTypeck,
MirBorrowck,
}
impl<'tcx> OpaqueHiddenType<'tcx> { impl<'tcx> OpaqueHiddenType<'tcx> {
pub fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> OpaqueHiddenType<'tcx> {
OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(tcx, guar) }
}
pub fn build_mismatch_error( pub fn build_mismatch_error(
&self, &self,
other: &Self, other: &Self,
@ -808,8 +823,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
self, self,
opaque_type_key: OpaqueTypeKey<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
// typeck errors have subpar spans for opaque types, so delay error reporting until borrowck. defining_scope_kind: DefiningScopeKind,
ignore_errors: bool,
) -> Self { ) -> Self {
let OpaqueTypeKey { def_id, args } = opaque_type_key; let OpaqueTypeKey { def_id, args } = opaque_type_key;
@ -828,10 +842,19 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
let map = args.iter().zip(id_args).collect(); let map = args.iter().zip(id_args).collect();
debug!("map = {:#?}", map); debug!("map = {:#?}", map);
// Convert the type from the function into a type valid outside // Convert the type from the function into a type valid outside by mapping generic
// the function, by replacing invalid regions with 'static, // parameters to into the context of the opaque.
// after producing an error for each of them. //
self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors)) // We erase regions when doing this during HIR typeck.
let this = match defining_scope_kind {
DefiningScopeKind::HirTypeck => tcx.erase_regions(self),
DefiningScopeKind::MirBorrowck => self,
};
let result = this.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span));
if cfg!(debug_assertions) && matches!(defining_scope_kind, DefiningScopeKind::HirTypeck) {
assert_eq!(result.ty, tcx.erase_regions(result.ty));
}
result
} }
} }

View file

@ -20,12 +20,6 @@ pub(super) struct ReverseMapper<'tcx> {
/// for an explanation of this field. /// for an explanation of this field.
do_not_error: bool, do_not_error: bool,
/// We do not want to emit any errors in typeck because
/// the spans in typeck are subpar at the moment.
/// Borrowck will do the same work again (this time with
/// lifetime information) and thus report better errors.
ignore_errors: bool,
/// Span of function being checked. /// Span of function being checked.
span: Span, span: Span,
} }
@ -35,9 +29,8 @@ impl<'tcx> ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
span: Span, span: Span,
ignore_errors: bool,
) -> Self { ) -> Self {
Self { tcx, map, do_not_error: false, ignore_errors, span } Self { tcx, map, do_not_error: false, span }
} }
fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
@ -176,8 +169,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
Some(u) => panic!("type mapped to unexpected kind: {u:?}"), Some(u) => panic!("type mapped to unexpected kind: {u:?}"),
None => { None => {
debug!(?param, ?self.map); debug!(?param, ?self.map);
if !self.ignore_errors { let guar = self
self.tcx .tcx
.dcx() .dcx()
.struct_span_err( .struct_span_err(
self.span, self.span,
@ -187,9 +180,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
), ),
) )
.emit(); .emit();
} Ty::new_error(self.tcx, guar)
Ty::new_misc_error(self.tcx)
} }
} }
} }
@ -217,8 +208,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
ct: ct.to_string(), ct: ct.to_string(),
span: self.span, span: self.span,
}) })
.emit_unless(self.ignore_errors); .emit();
ty::Const::new_error(self.tcx, guar) ty::Const::new_error(self.tcx, guar)
} }
} }

View file

@ -158,7 +158,7 @@ pub struct TypeckResults<'tcx> {
/// We also store the type here, so that the compiler can use it as a hint /// We also store the type here, so that the compiler can use it as a hint
/// for figuring out hidden types, even if they are only set in dead code /// for figuring out hidden types, even if they are only set in dead code
/// (which doesn't show up in MIR). /// (which doesn't show up in MIR).
pub concrete_opaque_types: FxIndexMap<ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>>, pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
/// Tracks the minimum captures required for a closure; /// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details. /// see `MinCaptureInformationMap` for more details.

View file

@ -330,6 +330,7 @@ where
// During analysis, opaques are rigid unless they may be defined by // During analysis, opaques are rigid unless they may be defined by
// the current body. // the current body.
TypingMode::Analysis { defining_opaque_types: non_rigid_opaques } TypingMode::Analysis { defining_opaque_types: non_rigid_opaques }
| TypingMode::Borrowck { defining_opaque_types: non_rigid_opaques }
| TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => { | TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => {
!def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id)) !def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id))
} }

View file

@ -96,6 +96,42 @@ where
); );
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} }
// Very similar to `TypingMode::Analysis` with some notably differences:
// - we accept opaque types even if they have non-universal arguments
// - we do a structural lookup instead of semantically unifying regions
// - the hidden type starts out as the type from HIR typeck with fresh region
// variables instead of a fully unconstrained inference variable
TypingMode::Borrowck { defining_opaque_types } => {
let Some(def_id) = opaque_ty
.def_id
.as_local()
.filter(|&def_id| defining_opaque_types.contains(&def_id))
else {
self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
};
let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
let actual = self
.register_hidden_type_in_storage(opaque_type_key, expected)
.unwrap_or_else(|| {
let actual =
cx.type_of_opaque_hir_typeck(def_id).instantiate(cx, opaque_ty.args);
let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() {
ty::ReErased => self.next_region_var(),
_ => re,
});
actual
});
self.eq(goal.param_env, expected, actual)?;
self.add_item_bounds_for_hidden_type(
def_id.into(),
opaque_ty.args,
goal.param_env,
expected,
);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
TypingMode::PostBorrowckAnalysis { defined_opaque_types } => { TypingMode::PostBorrowckAnalysis { defined_opaque_types } => {
let Some(def_id) = opaque_ty let Some(def_id) = opaque_ty
.def_id .def_id

View file

@ -62,6 +62,7 @@ where
response_no_constraints(cx, input, Certainty::overflow(false)) response_no_constraints(cx, input, Certainty::overflow(false))
} }
TypingMode::Analysis { .. } TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } | TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => Err(NoSolution), | TypingMode::PostAnalysis => Err(NoSolution),
}, },

View file

@ -72,6 +72,7 @@ where
(ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() { (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
TypingMode::Coherence => Certainty::AMBIGUOUS, TypingMode::Coherence => Certainty::AMBIGUOUS,
TypingMode::Analysis { .. } TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } | TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => return Err(NoSolution), | TypingMode::PostAnalysis => return Err(NoSolution),
}, },

View file

@ -135,7 +135,10 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
/// Returns the hidden type corresponding to this key if the body under analysis is allowed to /// Returns the hidden type corresponding to this key if the body under analysis is allowed to
/// know it. /// know it.
fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> { fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
self.typeck_results.concrete_opaque_types.get(&key).map(|x| x.ty) self.typeck_results
.concrete_opaque_types
.get(&key.def_id)
.map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args))
} }
// This can take a non-revealed `Ty` because it reveals opaques itself. // This can take a non-revealed `Ty` because it reveals opaques itself.
pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {

View file

@ -2555,6 +2555,9 @@ written to standard error output)"),
"in diagnostics, use heuristics to shorten paths referring to items"), "in diagnostics, use heuristics to shorten paths referring to items"),
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
"select processor to schedule for (`rustc --print target-cpus` for details)"), "select processor to schedule for (`rustc --print target-cpus` for details)"),
#[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_borrowck` instead of this field")]
typing_mode_borrowck: bool = (false, parse_bool, [TRACKED],
"enable `TypingMode::Borrowck`, changing the way opaque types are handled during MIR borrowck"),
#[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")]
ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED], ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
"emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"),

View file

@ -264,8 +264,15 @@ trait_selection_oc_no_diverge = `else` clause of `let...else` does not diverge
trait_selection_oc_no_else = `if` may be missing an `else` clause trait_selection_oc_no_else = `if` may be missing an `else` clause
trait_selection_oc_try_compat = `?` operator has incompatible types trait_selection_oc_try_compat = `?` operator has incompatible types
trait_selection_oc_type_compat = type not compatible with trait trait_selection_oc_type_compat = type not compatible with trait
trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
.label = opaque type defined here .label = opaque type defined here
trait_selection_opaque_type_non_generic_param =
expected generic {$kind} parameter, found `{$ty}`
.label = {STREQ($ty, "'static") ->
[true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
*[other] this generic parameter must be used with a generic {$kind} parameter
}
trait_selection_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type trait_selection_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
trait_selection_outlives_content = lifetime of reference outlives lifetime of borrowed content... trait_selection_outlives_content = lifetime of reference outlives lifetime of borrowed content...

View file

@ -12,7 +12,7 @@ use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node}; use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node};
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt}; use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt};
use rustc_span::{BytePos, Ident, Span, Symbol, kw}; use rustc_span::{BytePos, Ident, Span, Symbol, kw};
use crate::error_reporting::infer::ObligationCauseAsDiagArg; use crate::error_reporting::infer::ObligationCauseAsDiagArg;
@ -1922,3 +1922,14 @@ impl Subdiagnostic for AddPreciseCapturingForOvercapture {
} }
} }
} }
#[derive(Diagnostic)]
#[diag(trait_selection_opaque_type_non_generic_param, code = E0792)]
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
pub ty: GenericArg<'tcx>,
pub kind: &'a str,
#[primary_span]
pub span: Span,
#[label]
pub param_span: Span,
}

View file

@ -36,6 +36,7 @@
pub mod error_reporting; pub mod error_reporting;
pub mod errors; pub mod errors;
pub mod infer; pub mod infer;
pub mod opaque_types;
pub mod regions; pub mod regions;
pub mod solve; pub mod solve;
pub mod traits; pub mod traits;

View file

@ -0,0 +1,182 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::OpaqueTyOrigin;
use rustc_hir::def_id::LocalDefId;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::ty::{
self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, TyCtxt, TypeVisitableExt,
TypingMode, fold_regions,
};
use rustc_span::{ErrorGuaranteed, Span};
use crate::errors::NonGenericOpaqueTypeParam;
use crate::regions::OutlivesEnvironmentBuildExt;
use crate::traits::ObligationCtxt;
/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter].
///
/// [rustc-dev-guide chapter]:
/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
pub fn check_opaque_type_parameter_valid<'tcx>(
infcx: &InferCtxt<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>,
span: Span,
defining_scope_kind: DefiningScopeKind,
) -> Result<(), ErrorGuaranteed> {
let tcx = infcx.tcx;
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
// Avoid duplicate errors in case the opaque has already been malformed in
// HIR typeck.
if let DefiningScopeKind::MirBorrowck = defining_scope_kind {
if let Err(guar) = infcx
.tcx
.type_of_opaque_hir_typeck(opaque_type_key.def_id)
.instantiate_identity()
.error_reported()
{
return Err(guar);
}
}
for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
let arg_is_param = match arg.unpack() {
GenericArgKind::Lifetime(lt) => match defining_scope_kind {
DefiningScopeKind::HirTypeck => continue,
DefiningScopeKind::MirBorrowck => {
matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
|| (lt.is_static() && opaque_env.param_equal_static(i))
}
},
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
};
if arg_is_param {
// Register if the same lifetime appears multiple times in the generic args.
// There is an exception when the opaque type *requires* the lifetimes to be equal.
// See [rustc-dev-guide chapter] § "An exception to uniqueness rule".
let seen_where = seen_params.entry(arg).or_default();
if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) {
seen_where.push(i);
}
} else {
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = opaque_generics.param_at(i, tcx);
let kind = opaque_param.kind.descr();
opaque_env.param_is_error(i)?;
return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
ty: arg,
kind,
span,
param_span: tcx.def_span(opaque_param.def_id),
}));
}
}
for (_, indices) in seen_params {
if indices.len() > 1 {
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
let spans: Vec<_> = indices
.into_iter()
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
.collect();
return Err(infcx
.dcx()
.struct_span_err(span, "non-defining opaque type use in defining scope")
.with_span_note(spans, format!("{descr} used multiple times"))
.emit());
}
}
Ok(())
}
/// Computes if an opaque type requires a lifetime parameter to be equal to
/// another one or to the `'static` lifetime.
/// These requirements are derived from the explicit and implied bounds.
struct LazyOpaqueTyEnv<'tcx> {
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
/// Equal parameters will have the same name. Computed Lazily.
/// Example:
/// `type Opaque<'a: 'static, 'b: 'c, 'c: 'b> = impl Sized;`
/// Identity args: `['a, 'b, 'c]`
/// Canonical args: `['static, 'b, 'b]`
canonical_args: std::cell::OnceCell<ty::GenericArgsRef<'tcx>>,
}
impl<'tcx> LazyOpaqueTyEnv<'tcx> {
fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() }
}
fn param_equal_static(&self, param_index: usize) -> bool {
self.get_canonical_args()[param_index].expect_region().is_static()
}
fn params_equal(&self, param1: usize, param2: usize) -> bool {
let canonical_args = self.get_canonical_args();
canonical_args[param1] == canonical_args[param2]
}
fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> {
self.get_canonical_args()[param_index].error_reported()
}
fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
if let Some(&canonical_args) = self.canonical_args.get() {
return canonical_args;
}
let &Self { tcx, def_id, .. } = self;
let origin = tcx.local_opaque_ty_origin(def_id);
let parent = match origin {
OpaqueTyOrigin::FnReturn { parent, .. }
| OpaqueTyOrigin::AsyncFn { parent, .. }
| OpaqueTyOrigin::TyAlias { parent, .. } => parent,
};
let param_env = tcx.param_env(parent);
let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
tcx,
def_id.to_def_id(),
|param, _| {
tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
},
);
// FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're
// in a body here.
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new(&infcx);
let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
Default::default()
});
let outlives_env = OutlivesEnvironment::new(&infcx, parent, param_env, wf_tys);
let mut seen = vec![tcx.lifetimes.re_static];
let canonical_args = fold_regions(tcx, args, |r1, _| {
if r1.is_error() {
r1
} else if let Some(&r2) = seen.iter().find(|&&r2| {
let free_regions = outlives_env.free_region_map();
free_regions.sub_free_regions(tcx, r1, r2)
&& free_regions.sub_free_regions(tcx, r2, r1)
}) {
r2
} else {
seen.push(r1);
r1
}
});
self.canonical_args.set(canonical_args).unwrap();
canonical_args
}
}

View file

@ -195,6 +195,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
match self.typing_mode() { match self.typing_mode() {
TypingMode::Coherence TypingMode::Coherence
| TypingMode::Analysis { .. } | TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } => false, | TypingMode::PostBorrowckAnalysis { .. } => false,
TypingMode::PostAnalysis => { TypingMode::PostAnalysis => {
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);

View file

@ -130,6 +130,7 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
TypingMode::Coherence TypingMode::Coherence
| TypingMode::Analysis { .. } | TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE), | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
TypingMode::PostAnalysis => {} TypingMode::PostAnalysis => {}
} }
@ -226,6 +227,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
TypingMode::Coherence TypingMode::Coherence
| TypingMode::Analysis { .. } | TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self), | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
TypingMode::PostAnalysis => { TypingMode::PostAnalysis => {
let recursion_limit = self.cx().recursion_limit(); let recursion_limit = self.cx().recursion_limit();

View file

@ -952,6 +952,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
match selcx.infcx.typing_mode() { match selcx.infcx.typing_mode() {
TypingMode::Coherence TypingMode::Coherence
| TypingMode::Analysis { .. } | TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } => { | TypingMode::PostBorrowckAnalysis { .. } => {
debug!( debug!(
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),

View file

@ -216,6 +216,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
match self.infcx.typing_mode() { match self.infcx.typing_mode() {
TypingMode::Coherence TypingMode::Coherence
| TypingMode::Analysis { .. } | TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } => ty.try_super_fold_with(self)?, | TypingMode::PostBorrowckAnalysis { .. } => ty.try_super_fold_with(self)?,
TypingMode::PostAnalysis => { TypingMode::PostAnalysis => {

View file

@ -1446,6 +1446,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match self.infcx.typing_mode() { match self.infcx.typing_mode() {
TypingMode::Coherence => {} TypingMode::Coherence => {}
TypingMode::Analysis { .. } TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } | TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => return Ok(()), | TypingMode::PostAnalysis => return Ok(()),
} }
@ -1491,7 +1492,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// However, if we disqualify *all* goals from being cached, perf suffers. // However, if we disqualify *all* goals from being cached, perf suffers.
// This is likely fixed by better caching in general in the new solver. // This is likely fixed by better caching in general in the new solver.
// See: <https://github.com/rust-lang/rust/issues/132064>. // See: <https://github.com/rust-lang/rust/issues/132064>.
TypingMode::Analysis { defining_opaque_types } => { TypingMode::Analysis { defining_opaque_types }
| TypingMode::Borrowck { defining_opaque_types } => {
defining_opaque_types.is_empty() || !pred.has_opaque_types() defining_opaque_types.is_empty() || !pred.has_opaque_types()
} }
// The hidden types of `defined_opaque_types` is not local to the current // The hidden types of `defined_opaque_types` is not local to the current

View file

@ -149,6 +149,7 @@ fn resolve_associated_item<'tcx>(
match typing_env.typing_mode { match typing_env.typing_mode {
ty::TypingMode::Coherence ty::TypingMode::Coherence
| ty::TypingMode::Analysis { .. } | ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. } => false, | ty::TypingMode::PostBorrowckAnalysis { .. } => false,
ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(), ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
} }

View file

@ -66,6 +66,14 @@ pub enum TypingMode<I: Interner> {
/// } /// }
/// ``` /// ```
Analysis { defining_opaque_types: I::DefiningOpaqueTypes }, Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
/// The behavior during MIR borrowck is identical to `TypingMode::Analysis`
/// except that the initial value for opaque types is the type computed during
/// HIR typeck with unique unconstrained region inference variables.
///
/// This is currently only used with by the new solver as it results in new
/// non-universal defining uses of opaque types, which is a breaking change.
/// See tests/ui/impl-trait/non-defining-use/as-projection-term.rs.
Borrowck { defining_opaque_types: I::DefiningOpaqueTypes },
/// Any analysis after borrowck for a given body should be able to use all the /// Any analysis after borrowck for a given body should be able to use all the
/// hidden types defined by borrowck, without being able to define any new ones. /// hidden types defined by borrowck, without being able to define any new ones.
/// ///
@ -95,6 +103,10 @@ impl<I: Interner> TypingMode<I> {
TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
} }
pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
TypingMode::Borrowck { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
}
pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
TypingMode::PostBorrowckAnalysis { TypingMode::PostBorrowckAnalysis {
defined_opaque_types: cx.opaque_types_defined_by(body_def_id), defined_opaque_types: cx.opaque_types_defined_by(body_def_id),

View file

@ -149,6 +149,8 @@ pub trait Interner:
) -> Option<Self::VariancesOf>; ) -> Option<Self::VariancesOf>;
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>; fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
-> ty::EarlyBinder<Self, Self::Ty>;
type AdtDef: AdtDef<Self>; type AdtDef: AdtDef<Self>;
fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef; fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef;

View file

@ -137,6 +137,7 @@ where
Ok(a) Ok(a)
} }
TypingMode::Analysis { .. } TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } | TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b), | TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b),
} }

View file

@ -1,19 +0,0 @@
//@ known-bug: #112201
pub fn compose(
f1: impl FnOnce(f64) -> f64 + Clone,
f2: impl FnOnce(f64) -> f64 + Clone,
) -> impl FnOnce(f64) -> f64 + Clone {
move |x| f1(f2(x))
}
fn repeat_helper(
f: impl FnOnce(f64) -> f64 + Clone,
res: impl FnOnce(f64) -> f64 + Clone,
times: usize,
) -> impl FnOnce(f64) -> f64 + Clone {
return res;
repeat_helper(f.clone(), compose(f, res), times - 1)
}
fn main() {}

View file

@ -1,6 +0,0 @@
//@ known-bug: #137751
//@ compile-flags: --edition=2021 -Znext-solver=globally
async fn test() {
Box::pin(test()).await;
}
fn main() {}

View file

@ -35,11 +35,11 @@ note: ...which requires type-checking `foo::{closure#0}`...
LL | move |_: ()| { LL | move |_: ()| {
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
= note: ...which again requires type-checking `foo`, completing the cycle = note: ...which again requires type-checking `foo`, completing the cycle
note: cycle used when computing type of opaque `foo::{opaque#0}` note: cycle used when match-checking `foo`
--> $DIR/clone-rpit.rs:13:25 --> $DIR/clone-rpit.rs:13:1
| |
LL | pub fn foo<'a, 'b>() -> impl Clone { LL | pub fn foo<'a, 'b>() -> impl Clone {
| ^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -15,8 +15,8 @@ pub trait Trait2 {
impl<'c, S: Trait2> Trait2 for &'c mut S { impl<'c, S: Trait2> Trait2 for &'c mut S {
type FooFuture<'a> = impl Trait1; type FooFuture<'a> = impl Trait1;
//~^ ERROR unconstrained opaque type
fn foo<'a>() -> Self::FooFuture<'a> { fn foo<'a>() -> Self::FooFuture<'a> {
//~^ ERROR item does not constrain `<&'c mut S as Trait2>::FooFuture::{opaque#0}`
Struct(unimplemented!()) Struct(unimplemented!())
} }
} }

View file

@ -1,10 +1,15 @@
error: unconstrained opaque type error: item does not constrain `<&'c mut S as Trait2>::FooFuture::{opaque#0}`
--> $DIR/issue-87258_a.rs:18:8
|
LL | fn foo<'a>() -> Self::FooFuture<'a> {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/issue-87258_a.rs:17:26 --> $DIR/issue-87258_a.rs:17:26
| |
LL | type FooFuture<'a> = impl Trait1; LL | type FooFuture<'a> = impl Trait1;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
|
= note: `FooFuture` must be used in combination with a concrete type within the same impl
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -14,12 +14,12 @@ pub trait Trait2 {
} }
type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1; type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
//~^ ERROR unconstrained opaque type
impl<'c, S: Trait2> Trait2 for &'c mut S { impl<'c, S: Trait2> Trait2 for &'c mut S {
type FooFuture<'a> = Helper<'c, 'a, S>; type FooFuture<'a> = Helper<'c, 'a, S>;
#[define_opaque(Helper)] #[define_opaque(Helper)]
fn foo<'a>() -> Self::FooFuture<'a> { fn foo<'a>() -> Self::FooFuture<'a> {
//~^ ERROR item does not constrain `Helper::{opaque#0}`
Struct(unimplemented!()) Struct(unimplemented!())
} }
} }

View file

@ -1,10 +1,15 @@
error: unconstrained opaque type error: item does not constrain `Helper::{opaque#0}`
--> $DIR/issue-87258_b.rs:21:8
|
LL | fn foo<'a>() -> Self::FooFuture<'a> {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/issue-87258_b.rs:16:49 --> $DIR/issue-87258_b.rs:16:49
| |
LL | type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1; LL | type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
|
= note: `Helper` must be used in combination with a concrete type within the same crate
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -1,18 +1,5 @@
error: item does not constrain `Foo::{opaque#0}`
--> $DIR/norm-before-method-resolution-opaque-type.rs:17:4
|
LL | fn weird_bound<X>(x: &<X as Trait<'static>>::Out<Foo>) -> X
| ^^^^^^^^^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/norm-before-method-resolution-opaque-type.rs:14:12
|
LL | type Foo = impl Sized;
| ^^^^^^^^^^
error[E0507]: cannot move out of `*x` which is behind a shared reference error[E0507]: cannot move out of `*x` which is behind a shared reference
--> $DIR/norm-before-method-resolution-opaque-type.rs:23:13 --> $DIR/norm-before-method-resolution-opaque-type.rs:22:13
| |
LL | let x = *x; LL | let x = *x;
| ^^ move occurs because `*x` has type `<X as Trait<'_>>::Out<Foo>`, which does not implement the `Copy` trait | ^^ move occurs because `*x` has type `<X as Trait<'_>>::Out<Foo>`, which does not implement the `Copy` trait
@ -23,6 +10,6 @@ LL - let x = *x;
LL + let x = x; LL + let x = x;
| |
error: aborting due to 2 previous errors error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0507`. For more information about this error, try `rustc --explain E0507`.

View file

@ -15,7 +15,6 @@ type Foo = impl Sized;
#[define_opaque(Foo)] #[define_opaque(Foo)]
fn weird_bound<X>(x: &<X as Trait<'static>>::Out<Foo>) -> X fn weird_bound<X>(x: &<X as Trait<'static>>::Out<Foo>) -> X
//[old]~^ ERROR: item does not constrain
where where
for<'a> X: Trait<'a>, for<'a> X: Trait<'a>,
for<'a> <X as Trait<'a>>::Out<()>: Copy, for<'a> <X as Trait<'a>>::Out<()>: Copy,

View file

@ -13,6 +13,7 @@ impl<S: Default> Bar for S {
//~^ ERROR impl has stricter requirements than trait //~^ ERROR impl has stricter requirements than trait
//~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] //~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277]
//~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277]
//~| ERROR type parameter `T` is part of concrete type
(S::default(), T::default()) (S::default(), T::default())
} }
} }

View file

@ -37,7 +37,13 @@ help: consider further restricting type parameter `T` with trait `Copy`
LL | fn foo<T: Default + std::marker::Copy>() -> Self::E { LL | fn foo<T: Default + std::marker::Copy>() -> Self::E {
| +++++++++++++++++++ | +++++++++++++++++++
error: aborting due to 3 previous errors error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872-1.rs:12:29
|
LL | fn foo<T: Default>() -> Self::E {
| ^^^^^^^
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0276, E0277. Some errors have detailed explanations: E0276, E0277.
For more information about an error, try `rustc --explain E0276`. For more information about an error, try `rustc --explain E0276`.

View file

@ -11,9 +11,9 @@ pub trait Bar {
impl<S> Bar for S { impl<S> Bar for S {
type E = impl std::marker::Send; type E = impl std::marker::Send;
fn foo<T>() -> Self::E { fn foo<T>() -> Self::E {
async {}
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
//~| ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias //~| ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
async {}
} }
} }

View file

@ -1,14 +1,14 @@
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872-2.rs:14:9 --> $DIR/issue-55872-2.rs:13:20
| |
LL | async {} LL | fn foo<T>() -> Self::E {
| ^^^^^^^^ | ^^^^^^^
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872-2.rs:14:9 --> $DIR/issue-55872-2.rs:13:20
| |
LL | async {} LL | fn foo<T>() -> Self::E {
| ^^^^^^^^ | ^^^^^^^
| |
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

View file

@ -13,6 +13,7 @@ impl<S> Bar for S {
type E = impl std::marker::Copy; type E = impl std::marker::Copy;
fn foo<T>() -> Self::E { fn foo<T>() -> Self::E {
//~^ ERROR : Copy` is not satisfied [E0277] //~^ ERROR : Copy` is not satisfied [E0277]
//~| ERROR type parameter `T` is part of concrete type
async {} async {}
} }
} }

View file

@ -1,12 +1,18 @@
error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:16:9: 16:14}: Copy` is not satisfied error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}: Copy` is not satisfied
--> $DIR/issue-55872-3.rs:14:20 --> $DIR/issue-55872-3.rs:14:20
| |
LL | fn foo<T>() -> Self::E { LL | fn foo<T>() -> Self::E {
| ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:16:9: 16:14}` | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}`
LL | ...
LL | async {} LL | async {}
| -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:16:9: 16:14}` here | -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` here
error: aborting due to 1 previous error error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872-3.rs:14:20
|
LL | fn foo<T>() -> Self::E {
| ^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0277`.

View file

@ -10,8 +10,8 @@ impl<S> Bar for S {
type E = impl Copy; type E = impl Copy;
fn foo<T>() -> Self::E { fn foo<T>() -> Self::E {
|| ()
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
|| ()
} }
} }

View file

@ -1,8 +1,8 @@
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872.rs:13:9 --> $DIR/issue-55872.rs:12:20
| |
LL | || () LL | fn foo<T>() -> Self::E {
| ^^^^^ | ^^^^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -7,8 +7,7 @@ fn main() {
fn test<T: Display>(t: T, recurse: bool) -> impl Display { fn test<T: Display>(t: T, recurse: bool) -> impl Display {
let f = || { let f = || {
let i: u32 = test::<i32>(-1, false); let i: u32 = test::<i32>(-1, false);
//~^ ERROR concrete type differs from previous defining opaque type use //~^ ERROR expected generic type parameter, found `i32`
//~| ERROR expected generic type parameter, found `i32`
println!("{i}"); println!("{i}");
}; };
if recurse { if recurse {

View file

@ -1,15 +1,3 @@
error: concrete type differs from previous defining opaque type use
--> $DIR/issue-99073-2.rs:9:22
|
LL | let i: u32 = test::<i32>(-1, false);
| ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32`
|
note: previous use here
--> $DIR/issue-99073-2.rs:7:45
|
LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
| ^^^^^^^^^^^^
error[E0792]: expected generic type parameter, found `i32` error[E0792]: expected generic type parameter, found `i32`
--> $DIR/issue-99073-2.rs:9:22 --> $DIR/issue-99073-2.rs:9:22
| |
@ -19,6 +7,6 @@ LL | let f = || {
LL | let i: u32 = test::<i32>(-1, false); LL | let i: u32 = test::<i32>(-1, false);
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0792`. For more information about this error, try `rustc --explain E0792`.

View file

@ -4,6 +4,5 @@ fn main() {
fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() { fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
move || f(fix(&f)) move || f(fix(&f))
//~^ ERROR concrete type differs from previous defining opaque type use //~^ ERROR expected generic type parameter, found `&F`
//~| ERROR expected generic type parameter, found `&F`
} }

View file

@ -1,23 +1,11 @@
error: concrete type differs from previous defining opaque type use
--> $DIR/issue-99073.rs:6:13
|
LL | move || f(fix(&f))
| ^^^^^^^ expected `{closure@$DIR/issue-99073.rs:6:3: 6:10}`, got `G`
|
note: previous use here
--> $DIR/issue-99073.rs:5:36
|
LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
| ^^^^^^^^^
error[E0792]: expected generic type parameter, found `&F` error[E0792]: expected generic type parameter, found `&F`
--> $DIR/issue-99073.rs:6:11 --> $DIR/issue-99073.rs:6:13
| |
LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() { LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
| - this generic parameter must be used with a generic type parameter | - this generic parameter must be used with a generic type parameter
LL | move || f(fix(&f)) LL | move || f(fix(&f))
| ^^^^^^^^^^ | ^^^^^^^
error: aborting due to 2 previous errors error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0792`. For more information about this error, try `rustc --explain E0792`.

View file

@ -0,0 +1,17 @@
// Regression test for #112201. This recursive call previously meant that
// we delay an error when checking opaques at the end of writeback but don't
// encounter that incorrect defining use during borrowck as it's in dead code.
pub fn wrap<T>(x: T) -> impl Sized {
x
}
fn repeat_helper<T>(x: T) -> impl Sized {
return x;
repeat_helper(wrap(x))
//~^ ERROR expected generic type parameter, found `impl Sized`
//~| ERROR type parameter `T` is part of concrete type
}
fn main() {}

View file

@ -0,0 +1,18 @@
error[E0792]: expected generic type parameter, found `impl Sized`
--> $DIR/fuzzer-ice-issue-112201.rs:11:5
|
LL | fn repeat_helper<T>(x: T) -> impl Sized {
| - this generic parameter must be used with a generic type parameter
LL | return x;
LL | repeat_helper(wrap(x))
| ^^^^^^^^^^^^^^^^^^^^^^
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/fuzzer-ice-issue-112201.rs:11:5
|
LL | repeat_helper(wrap(x))
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0792`.

View file

@ -29,7 +29,6 @@ where
F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f, F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f,
{ {
f f
//~^ ERROR expected generic lifetime parameter, found `'_`
} }
impl Context { impl Context {
@ -39,7 +38,6 @@ impl Context {
&self, &self,
f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>,
) -> TransactionResult<O> { ) -> TransactionResult<O> {
//~^ ERROR expected generic lifetime parameter, found `'_`
let mut conn = Connection {}; let mut conn = Connection {};
let mut transaction = TestTransaction { conn: &mut conn }; let mut transaction = TestTransaction { conn: &mut conn };
f(&mut transaction).await f(&mut transaction).await

View file

@ -12,7 +12,7 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResu
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: item does not constrain `TransactionFuture::{opaque#0}` error: item does not constrain `TransactionFuture::{opaque#0}`
--> $DIR/issue-86800.rs:37:14 --> $DIR/issue-86800.rs:36:14
| |
LL | async fn do_transaction<O>( LL | async fn do_transaction<O>(
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
@ -24,30 +24,5 @@ note: this opaque type is supposed to be constrained
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>; LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0792]: expected generic lifetime parameter, found `'_` error: aborting due to 2 previous errors
--> $DIR/issue-86800.rs:31:5
|
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
| --- this generic parameter must be used with a generic lifetime parameter
...
LL | f
| ^
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/issue-86800.rs:41:31
|
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
| --- this generic parameter must be used with a generic lifetime parameter
...
LL | ) -> TransactionResult<O> {
| _______________________________^
LL | |
LL | | let mut conn = Connection {};
LL | | let mut transaction = TestTransaction { conn: &mut conn };
LL | | f(&mut transaction).await
LL | | }
| |_____^
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0792`.

View file

@ -0,0 +1,12 @@
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/as-projection-term.rs:14:19
|
LL | fn recur<'a>() -> impl Sized + 'a {
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | prove_proj(|| recur());
| ^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0792`.

View file

@ -0,0 +1,17 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[current] check-pass
fn prove_proj<R>(_: impl FnOnce() -> R) {}
fn recur<'a>() -> impl Sized + 'a {
// The closure has the signature `fn() -> opaque<'1>`. `prove_proj`
// requires us to prove `<closure as FnOnce<()>>::Output = opaque<'2>`.
// The old solver uses `replace_opaque_types_with_infer` during normalization
// to replace `opaque<'2>` with its hidden type. If that hidden type is still an
// inference variable at this point, we unify it with `opaque<'1>` and
// end up ignoring that defining use as the hidden type is equal to its key.
prove_proj(|| recur());
//[next]~^ ERROR expected generic lifetime parameter, found `'_`
}
fn main() {}

View file

@ -1,3 +1,12 @@
error[E0792]: expected generic type parameter, found `&str`
--> $DIR/recursive-ice-101862.rs:6:19
|
LL | pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
| --------------- this generic parameter must be used with a generic type parameter
LL |
LL | vec![].append(&mut ice(x.as_ref()));
| ^^^^^^^^^^^^^^^^^^^^
warning: function cannot return without recursing warning: function cannot return without recursing
--> $DIR/recursive-ice-101862.rs:4:1 --> $DIR/recursive-ice-101862.rs:4:1
| |
@ -10,15 +19,6 @@ LL | vec![].append(&mut ice(x.as_ref()));
= help: a `loop` may express intention better if this is on purpose = help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default = note: `#[warn(unconditional_recursion)]` on by default
error[E0792]: expected generic type parameter, found `&str`
--> $DIR/recursive-ice-101862.rs:6:19
|
LL | pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
| --------------- this generic parameter must be used with a generic type parameter
LL |
LL | vec![].append(&mut ice(x.as_ref()));
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error; 1 warning emitted error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0792`. For more information about this error, try `rustc --explain E0792`.

View file

@ -1,11 +1,10 @@
use std::convert::identity; use std::convert::identity;
fn test<'a: 'a>(n: bool) -> impl Sized + 'a { fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
//~^ ERROR concrete type differs from previous defining opaque type use
let true = n else { loop {} }; let true = n else { loop {} };
let _ = || { let _ = || {
let _ = identity::<&'a ()>(test(false)); let _ = identity::<&'a ()>(test(false));
//~^ ERROR expected generic lifetime parameter, found `'_` //~^ ERROR concrete type differs from previous defining opaque type use
}; };
loop {} loop {}
} }

View file

@ -1,24 +1,14 @@
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/early_bound.rs:6:36
|
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^ expected `()`, got `&()`
|
note: previous use here
--> $DIR/early_bound.rs:3:29 --> $DIR/early_bound.rs:3:29
| |
LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a { LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
| ^^^^^^^^^^^^^^^ expected `&()`, got `()` | ^^^^^^^^^^^^^^^
|
note: previous use here
--> $DIR/early_bound.rs:7:36
|
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^
error[E0792]: expected generic lifetime parameter, found `'_` error: aborting due to 1 previous error
--> $DIR/early_bound.rs:7:17
|
LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0792`.

View file

@ -6,8 +6,7 @@ fn foo<T>() -> impl Sized {
fn bar<T>(val: T) -> impl Sized { fn bar<T>(val: T) -> impl Sized {
let _: u8 = bar(0u8); let _: u8 = bar(0u8);
//~^ ERROR concrete type differs from previous defining opaque type use //~^ ERROR expected generic type parameter, found `u8`
//~| ERROR expected generic type parameter, found `u8`
val val
} }

View file

@ -1,31 +1,19 @@
error[E0792]: expected generic type parameter, found `u8` error[E0792]: expected generic type parameter, found `u8`
--> $DIR/non-defining-use.rs:4:12 --> $DIR/non-defining-use.rs:4:17
| |
LL | fn foo<T>() -> impl Sized { LL | fn foo<T>() -> impl Sized {
| - this generic parameter must be used with a generic type parameter | - this generic parameter must be used with a generic type parameter
LL | let _: () = foo::<u8>(); LL | let _: () = foo::<u8>();
| ^^ | ^^^^^^^^^^^
error: concrete type differs from previous defining opaque type use
--> $DIR/non-defining-use.rs:8:17
|
LL | let _: u8 = bar(0u8);
| ^^^^^^^^ expected `T`, got `u8`
|
note: previous use here
--> $DIR/non-defining-use.rs:7:22
|
LL | fn bar<T>(val: T) -> impl Sized {
| ^^^^^^^^^^
error[E0792]: expected generic type parameter, found `u8` error[E0792]: expected generic type parameter, found `u8`
--> $DIR/non-defining-use.rs:8:12 --> $DIR/non-defining-use.rs:8:17
| |
LL | fn bar<T>(val: T) -> impl Sized { LL | fn bar<T>(val: T) -> impl Sized {
| - this generic parameter must be used with a generic type parameter | - this generic parameter must be used with a generic type parameter
LL | let _: u8 = bar(0u8); LL | let _: u8 = bar(0u8);
| ^^ | ^^^^^^^^
error: aborting due to 3 previous errors error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0792`. For more information about this error, try `rustc --explain E0792`.

View file

@ -9,6 +9,31 @@ note: ...which requires computing type of opaque `foo::{opaque#0}`...
| |
LL | fn foo() -> impl Sized { LL | fn foo() -> impl Sized {
| ^^^^^^^^^^ | ^^^^^^^^^^
note: ...which requires borrow-checking `foo`...
--> $DIR/in-defining-scope.rs:6:1
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `foo`...
--> $DIR/in-defining-scope.rs:6:1
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires checking if `foo` contains FFI-unwind calls...
--> $DIR/in-defining-scope.rs:6:1
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `foo`...
--> $DIR/in-defining-scope.rs:6:1
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires match-checking `foo`...
--> $DIR/in-defining-scope.rs:6:1
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `foo`... note: ...which requires type-checking `foo`...
--> $DIR/in-defining-scope.rs:6:1 --> $DIR/in-defining-scope.rs:6:1
| |

View file

@ -1,18 +1,5 @@
error: item does not constrain `A::{opaque#0}`
--> $DIR/two_tait_defining_each_other2.rs:12:4
|
LL | fn muh(x: A) -> B {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/two_tait_defining_each_other2.rs:6:10
|
LL | type A = impl Foo;
| ^^^^^^^^
error: opaque type's hidden type cannot be another opaque type from the same scope error: opaque type's hidden type cannot be another opaque type from the same scope
--> $DIR/two_tait_defining_each_other2.rs:15:5 --> $DIR/two_tait_defining_each_other2.rs:14:5
| |
LL | x // B's hidden type is A (opaquely) LL | x // B's hidden type is A (opaquely)
| ^ one of the two opaque types used here has to be outside its defining scope | ^ one of the two opaque types used here has to be outside its defining scope
@ -28,5 +15,5 @@ note: opaque type being used as hidden type
LL | type A = impl Foo; LL | type A = impl Foo;
| ^^^^^^^^ | ^^^^^^^^
error: aborting due to 2 previous errors error: aborting due to 1 previous error

View file

@ -10,8 +10,7 @@ trait Foo {}
#[define_opaque(A, B)] #[define_opaque(A, B)]
fn muh(x: A) -> B { fn muh(x: A) -> B {
//[current]~^ ERROR: item does not constrain `A::{opaque#0}` //[next]~^ ERROR: cannot satisfy `_ == A`
//[next]~^^ ERROR: cannot satisfy `_ == A`
x // B's hidden type is A (opaquely) x // B's hidden type is A (opaquely)
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type //[current]~^ ERROR opaque type's hidden type cannot be another opaque type
} }

View file

@ -1,5 +1,8 @@
//@ known-bug: #132335 // Regression test for #132335. This previously ICE'd due to ambiguity
// in MIR typeck.
//@ compile-flags: -Znext-solver=globally --crate-type lib --edition=2018 //@ compile-flags: -Znext-solver=globally --crate-type lib --edition=2018
//@ check-pass
use core::future::Future; use core::future::Future;
use core::pin::Pin; use core::pin::Pin;

View file

@ -1,34 +1,54 @@
error: unconstrained opaque type error: item does not constrain `ex1::Tait1::{opaque#0}`
--> $DIR/no-define-in-wf-check.rs:21:8
|
LL | fn foo(x: Tait1) -> impl Sized {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/no-define-in-wf-check.rs:19:18 --> $DIR/no-define-in-wf-check.rs:19:18
| |
LL | type Tait1 = impl Sized; LL | type Tait1 = impl Sized;
| ^^^^^^^^^^ | ^^^^^^^^^^
|
= note: `Tait1` must be used in combination with a concrete type within the same crate
error: unconstrained opaque type error: item does not constrain `ex2::Tait1::{opaque#0}`
--> $DIR/no-define-in-wf-check.rs:31:8
|
LL | fn foo(x: Tait1) -> Tait2 {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/no-define-in-wf-check.rs:28:18 --> $DIR/no-define-in-wf-check.rs:28:18
| |
LL | type Tait1 = impl Sized; LL | type Tait1 = impl Sized;
| ^^^^^^^^^^ | ^^^^^^^^^^
|
= note: `Tait1` must be used in combination with a concrete type within the same crate
error: unconstrained opaque type error: item does not constrain `ex3::Tait1::{opaque#0}`
--> $DIR/no-define-in-wf-check.rs:43:8
|
LL | fn foo(x: Tait1) -> Tait2 {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/no-define-in-wf-check.rs:38:18 --> $DIR/no-define-in-wf-check.rs:38:18
| |
LL | type Tait1 = impl Sized; LL | type Tait1 = impl Sized;
| ^^^^^^^^^^ | ^^^^^^^^^^
|
= note: `Tait1` must be used in combination with a concrete type within the same crate
error: unconstrained opaque type error: item does not constrain `ex4::Tait1::{opaque#0}`
--> $DIR/no-define-in-wf-check.rs:64:8
|
LL | fn foo(x: Tait1) -> Tait2 {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/no-define-in-wf-check.rs:50:18 --> $DIR/no-define-in-wf-check.rs:50:18
| |
LL | type Tait1 = impl Sized; LL | type Tait1 = impl Sized;
| ^^^^^^^^^^ | ^^^^^^^^^^
|
= note: `Tait1` must be used in combination with a concrete type within the same crate
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View file

@ -17,38 +17,37 @@ mod ex0 {
} }
mod ex1 { mod ex1 {
type Tait1 = impl Sized; type Tait1 = impl Sized;
//[current]~^ ERROR unconstrained opaque type
#[define_opaque(Tait1)] #[define_opaque(Tait1)]
fn foo(x: Tait1) -> impl Sized { fn foo(x: Tait1) -> impl Sized {
//[current]~^ ERROR item does not constrain `ex1::Tait1::{opaque#0}`
let () = x; let () = x;
} }
} }
mod ex2 { mod ex2 {
type Tait1 = impl Sized; type Tait1 = impl Sized;
//[current]~^ ERROR unconstrained opaque type
type Tait2 = impl Sized; type Tait2 = impl Sized;
#[define_opaque(Tait1, Tait2)] #[define_opaque(Tait1, Tait2)]
fn foo(x: Tait1) -> Tait2 { fn foo(x: Tait1) -> Tait2 {
//[current]~^ ERROR item does not constrain `ex2::Tait1::{opaque#0}`
let () = x; let () = x;
} }
} }
mod ex3 { mod ex3 {
type Tait1 = impl Sized; type Tait1 = impl Sized;
//[current]~^ ERROR unconstrained opaque type
trait Something<T> {} trait Something<T> {}
impl<T, U> Something<U> for T {} impl<T, U> Something<U> for T {}
type Tait2 = impl Something<Tait1>; type Tait2 = impl Something<Tait1>;
#[define_opaque(Tait1, Tait2)] #[define_opaque(Tait1, Tait2)]
fn foo(x: Tait1) -> Tait2 { fn foo(x: Tait1) -> Tait2 {
//[current]~^ ERROR item does not constrain `ex3::Tait1::{opaque#0}`
let () = x; let () = x;
} }
} }
mod ex4 { mod ex4 {
type Tait1 = impl Sized; type Tait1 = impl Sized;
//[current]~^ ERROR unconstrained opaque type
trait Trait<U> { trait Trait<U> {
type Assoc; type Assoc;
} }
@ -63,6 +62,7 @@ mod ex4 {
type Tait2 = impl Trait<(), Assoc = impl Trait<Tait1>>; type Tait2 = impl Trait<(), Assoc = impl Trait<Tait1>>;
#[define_opaque(Tait1, Tait2)] #[define_opaque(Tait1, Tait2)]
fn foo(x: Tait1) -> Tait2 { fn foo(x: Tait1) -> Tait2 {
//[current]~^ ERROR item does not constrain `ex4::Tait1::{opaque#0}`
let () = x; let () = x;
} }
} }

View file

@ -0,0 +1,11 @@
// Regression test for #137751. This previously ICE'd as
// we did not provide the hidden type of the opaque inside
// of the async block. This caused borrowck of the recursive
// call to ICE.
//@ compile-flags: --edition=2021
//@ check-pass
async fn test() {
Box::pin(test()).await;
}
fn main() {}

View file

@ -12,7 +12,6 @@ pub enum UninhabitedVariants {
#[define_opaque(Alias)] #[define_opaque(Alias)]
fn uwu(x: UninhabitedVariants) { fn uwu(x: UninhabitedVariants) {
//~^ ERROR item does not constrain
match x {} match x {}
//~^ ERROR non-exhaustive patterns //~^ ERROR non-exhaustive patterns
} }

View file

@ -26,21 +26,8 @@ help: add missing generic argument
LL | Tuple(Alias<U>), LL | Tuple(Alias<U>),
| +++ | +++
error: item does not constrain `Alias::{opaque#0}`
--> $DIR/bad-tait-no-substs.rs:14:4
|
LL | fn uwu(x: UninhabitedVariants) {
| ^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> $DIR/bad-tait-no-substs.rs:5:21
|
LL | type Alias<'a, U> = impl Trait<U>;
| ^^^^^^^^^^^^^
error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` not covered error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` not covered
--> $DIR/bad-tait-no-substs.rs:16:11 --> $DIR/bad-tait-no-substs.rs:15:11
| |
LL | match x {} LL | match x {}
| ^ pattern `UninhabitedVariants::Tuple(_)` not covered | ^ pattern `UninhabitedVariants::Tuple(_)` not covered
@ -60,7 +47,7 @@ LL + UninhabitedVariants::Tuple(_) => todo!(),
LL ~ } LL ~ }
| |
error: aborting due to 4 previous errors error: aborting due to 3 previous errors
Some errors have detailed explanations: E0004, E0106, E0107. Some errors have detailed explanations: E0004, E0106, E0107.
For more information about an error, try `rustc --explain E0004`. For more information about an error, try `rustc --explain E0004`.

View file

@ -14,6 +14,6 @@ impl<W> Trait<W> for () {}
#[define_opaque(Foo)] #[define_opaque(Foo)]
fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
()
//~^ ERROR expected generic type parameter, found `<T as TraitWithAssoc>::Assoc` //~^ ERROR expected generic type parameter, found `<T as TraitWithAssoc>::Assoc`
()
} }

View file

@ -1,11 +1,11 @@
error[E0792]: expected generic type parameter, found `<T as TraitWithAssoc>::Assoc` error[E0792]: expected generic type parameter, found `<T as TraitWithAssoc>::Assoc`
--> $DIR/bound_reduction2.rs:17:5 --> $DIR/bound_reduction2.rs:16:46
| |
LL | type Foo<V> = impl Trait<V>; LL | type Foo<V> = impl Trait<V>;
| - this generic parameter must be used with a generic type parameter | - this generic parameter must be used with a generic type parameter
... ...
LL | () LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
| ^^ | ^^^^^^^^^^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -9,7 +9,7 @@ fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> {
#[define_opaque(Opaque)] #[define_opaque(Opaque)]
fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> { fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
//~^ ERROR: item does not constrain //~^ ERROR item does not constrain `Opaque::{opaque#0}`
None::<Opaque<'static>> None::<Opaque<'static>>
} }

View file

@ -12,6 +12,6 @@ fn foo() -> Foo {
#[define_opaque(Foo)] #[define_opaque(Foo)]
fn bar() -> Foo { fn bar() -> Foo {
//~^ ERROR concrete type differs
42i32 42i32
//~^ ERROR concrete type differs from previous
} }

View file

@ -1,14 +1,14 @@
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/different_defining_uses.rs:15:5 --> $DIR/different_defining_uses.rs:14:13
| |
LL | 42i32 LL | fn bar() -> Foo {
| ^^^^^ expected `&'static str`, got `i32` | ^^^ expected `&str`, got `i32`
| |
note: previous use here note: previous use here
--> $DIR/different_defining_uses.rs:10:5 --> $DIR/different_defining_uses.rs:9:13
| |
LL | "" LL | fn foo() -> Foo {
| ^^ | ^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -12,7 +12,6 @@ fn foo<'a, 'b>() -> Tait<'a> {
} }
let x: Tait<'a> = (); let x: Tait<'a> = ();
x x
//~^ ERROR concrete type differs from previous defining opaque type use
} }
fn main() {} fn main() {}

View file

@ -1,15 +1,3 @@
error: concrete type differs from previous defining opaque type use
--> $DIR/different_defining_uses_never_type-2.rs:14:5
|
LL | x
| ^ expected `i32`, got `()`
|
note: previous use here
--> $DIR/different_defining_uses_never_type-2.rs:9:31
|
LL | let y: Tait<'b> = 1i32;
| ^^^^
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/different_defining_uses_never_type-2.rs:9:31 --> $DIR/different_defining_uses_never_type-2.rs:9:31
| |
@ -17,10 +5,10 @@ LL | let y: Tait<'b> = 1i32;
| ^^^^ expected `()`, got `i32` | ^^^^ expected `()`, got `i32`
| |
note: previous use here note: previous use here
--> $DIR/different_defining_uses_never_type-2.rs:8:14 --> $DIR/different_defining_uses_never_type-2.rs:14:5
| |
LL | if { return } { LL | x
| ^^^^^^ | ^
error: aborting due to 2 previous errors error: aborting due to 1 previous error

View file

@ -5,10 +5,10 @@ LL | let y: Tait<U> = 1i32;
| ^^^^ expected `()`, got `i32` | ^^^^ expected `()`, got `i32`
| |
note: previous use here note: previous use here
--> $DIR/different_defining_uses_never_type-3.rs:13:22 --> $DIR/different_defining_uses_never_type-3.rs:14:5
| |
LL | let x: Tait<T> = (); LL | x
| ^^ | ^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -2,13 +2,13 @@ error: concrete type differs from previous defining opaque type use
--> $DIR/different_defining_uses_never_type.rs:14:13 --> $DIR/different_defining_uses_never_type.rs:14:13
| |
LL | fn bar() -> Foo { LL | fn bar() -> Foo {
| ^^^ expected `&'static str`, got `()` | ^^^ expected `&str`, got `()`
| |
note: previous use here note: previous use here
--> $DIR/different_defining_uses_never_type.rs:10:5 --> $DIR/different_defining_uses_never_type.rs:9:13
| |
LL | "" LL | fn foo() -> Foo {
| ^^ | ^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -5,10 +5,10 @@ LL | fn two() -> Tait { Two::<()>(todo!()) }
| ^^^^ expected `One`, got `Two<()>` | ^^^^ expected `One`, got `Two<()>`
| |
note: previous use here note: previous use here
--> $DIR/different_defining_uses_never_type3.rs:7:20 --> $DIR/different_defining_uses_never_type3.rs:7:13
| |
LL | fn one() -> Tait { One } LL | fn one() -> Tait { One }
| ^^^ | ^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -31,7 +31,6 @@ impl<F: for<'a> Fn(&'a ()) -> StateWidget<'a>> Widget<()> for StatefulWidget<F>
fn new_stateful_widget<F: for<'a> Fn(&'a ()) -> StateWidget<'a>>(build: F) -> impl Widget<()> { fn new_stateful_widget<F: for<'a> Fn(&'a ()) -> StateWidget<'a>>(build: F) -> impl Widget<()> {
//~^ ERROR item does not constrain //~^ ERROR item does not constrain
StatefulWidget(build) StatefulWidget(build)
//~^ ERROR expected generic lifetime parameter, found `'a`
} }
fn main() { fn main() {

View file

@ -24,17 +24,8 @@ note: this opaque type is supposed to be constrained
LL | type StateWidget<'a> = impl Widget<&'a ()>; LL | type StateWidget<'a> = impl Widget<&'a ()>;
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
error[E0792]: expected generic lifetime parameter, found `'a`
--> $DIR/failed-to-normalize-ice-99945.rs:33:5
|
LL | type StateWidget<'a> = impl Widget<&'a ()>;
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | StatefulWidget(build)
| ^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/failed-to-normalize-ice-99945.rs:38:29 --> $DIR/failed-to-normalize-ice-99945.rs:37:29
| |
LL | type StateWidget<'a> = impl Widget<&'a ()>; LL | type StateWidget<'a> = impl Widget<&'a ()>;
| ------------------- the expected opaque type | ------------------- the expected opaque type
@ -45,7 +36,6 @@ LL | new_stateful_widget(|_| ()).make_state();
= note: expected opaque type `StateWidget<'_>` = note: expected opaque type `StateWidget<'_>`
found unit type `()` found unit type `()`
error: aborting due to 4 previous errors error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0792. For more information about this error, try `rustc --explain E0308`.
For more information about an error, try `rustc --explain E0308`.

View file

@ -11,6 +11,6 @@ fn my_iter<T>(t: T) -> MyIter<T> {
#[define_opaque(MyIter)] #[define_opaque(MyIter)]
fn my_iter2<T>(t: T) -> MyIter<T> { fn my_iter2<T>(t: T) -> MyIter<T> {
Some(t).into_iter()
//~^ ERROR concrete type differs from previous //~^ ERROR concrete type differs from previous
Some(t).into_iter()
} }

View file

@ -1,14 +1,14 @@
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/generic_different_defining_uses.rs:14:5 --> $DIR/generic_different_defining_uses.rs:13:25
| |
LL | Some(t).into_iter() LL | fn my_iter2<T>(t: T) -> MyIter<T> {
| ^^^^^^^^^^^^^^^^^^^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>` | ^^^^^^^^^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
| |
note: previous use here note: previous use here
--> $DIR/generic_different_defining_uses.rs:9:5 --> $DIR/generic_different_defining_uses.rs:8:24
| |
LL | std::iter::once(t) LL | fn my_iter<T>(t: T) -> MyIter<T> {
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -20,8 +20,8 @@ type TwoConsts<const X: usize, const Y: usize> = impl Debug;
#[define_opaque(TwoTys)] #[define_opaque(TwoTys)]
fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> { fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
t
//~^ ERROR non-defining opaque type use in defining scope //~^ ERROR non-defining opaque type use in defining scope
t
} }
#[define_opaque(TwoLifetimes)] #[define_opaque(TwoLifetimes)]
@ -32,6 +32,6 @@ fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
#[define_opaque(TwoConsts)] #[define_opaque(TwoConsts)]
fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> { fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> {
t
//~^ ERROR non-defining opaque type use in defining scope //~^ ERROR non-defining opaque type use in defining scope
t
} }

View file

@ -1,8 +1,8 @@
error: non-defining opaque type use in defining scope error: non-defining opaque type use in defining scope
--> $DIR/generic_duplicate_param_use.rs:23:5 --> $DIR/generic_duplicate_param_use.rs:22:30
| |
LL | t LL | fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
| ^ | ^^^^^^^^^^^^
| |
note: type used multiple times note: type used multiple times
--> $DIR/generic_duplicate_param_use.rs:15:13 --> $DIR/generic_duplicate_param_use.rs:15:13
@ -23,10 +23,10 @@ LL | type TwoLifetimes<'a, 'b> = impl Debug;
| ^^ ^^ | ^^ ^^
error: non-defining opaque type use in defining scope error: non-defining opaque type use in defining scope
--> $DIR/generic_duplicate_param_use.rs:35:5 --> $DIR/generic_duplicate_param_use.rs:34:50
| |
LL | t LL | fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> {
| ^ | ^^^^^^^^^^^^^^^
| |
note: constant used multiple times note: constant used multiple times
--> $DIR/generic_duplicate_param_use.rs:19:16 --> $DIR/generic_duplicate_param_use.rs:19:16

View file

@ -14,6 +14,6 @@ fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
#[define_opaque(Two)] #[define_opaque(Two)]
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> { fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
u
//~^ ERROR concrete type differs //~^ ERROR concrete type differs
u
} }

View file

@ -1,14 +1,14 @@
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use3.rs:17:5 --> $DIR/generic_duplicate_param_use3.rs:16:38
| |
LL | u LL | fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
| ^ expected `T`, got `U` | ^^^^^^^^^ expected `T`, got `U`
| |
note: previous use here note: previous use here
--> $DIR/generic_duplicate_param_use3.rs:12:5 --> $DIR/generic_duplicate_param_use3.rs:11:36
| |
LL | t LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
| ^ | ^^^^^^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -14,6 +14,6 @@ fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
#[define_opaque(Two)] #[define_opaque(Two)]
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> { fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
(u, t)
//~^ ERROR concrete type differs //~^ ERROR concrete type differs
(u, t)
} }

View file

@ -1,14 +1,14 @@
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use5.rs:17:5 --> $DIR/generic_duplicate_param_use5.rs:16:45
| |
LL | (u, t) LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
| ^^^^^^ expected `(T, U)`, got `(U, T)` | ^^^^^^^^^ expected `(T, U)`, got `(U, T)`
| |
note: previous use here note: previous use here
--> $DIR/generic_duplicate_param_use5.rs:12:5 --> $DIR/generic_duplicate_param_use5.rs:11:43
| |
LL | (t, u) LL | fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
| ^^^^^^ | ^^^^^^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -14,6 +14,6 @@ fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
#[define_opaque(Two)] #[define_opaque(Two)]
fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> { fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
(u, t)
//~^ ERROR concrete type differs //~^ ERROR concrete type differs
(u, t)
} }

View file

@ -1,14 +1,14 @@
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use6.rs:17:5 --> $DIR/generic_duplicate_param_use6.rs:16:52
| |
LL | (u, t) LL | fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
| ^^^^^^ expected `(T, T)`, got `(U, T)` | ^^^^^^^^^ expected `(T, T)`, got `(U, T)`
| |
note: previous use here note: previous use here
--> $DIR/generic_duplicate_param_use6.rs:12:5 --> $DIR/generic_duplicate_param_use6.rs:11:50
| |
LL | (t, t) LL | fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
| ^^^^^^ | ^^^^^^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -13,6 +13,6 @@ fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
#[define_opaque(Two)] #[define_opaque(Two)]
fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> { fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
(u, 4u32)
//~^ concrete type differs //~^ concrete type differs
(u, 4u32)
} }

View file

@ -1,13 +1,13 @@
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use8.rs:16:5 --> $DIR/generic_duplicate_param_use8.rs:15:45
| |
LL | (u, 4u32) LL | fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
| ^^^^^^^^^ expected `(T, u32)`, got `(U, u32)` | ^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
| |
note: previous use here note: previous use here
--> $DIR/generic_duplicate_param_use8.rs:11:5 --> $DIR/generic_duplicate_param_use8.rs:10:43
| |
LL | (t, 4u32) LL | fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
| ^^^^^^^^^ | ^^^^^^^^^
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -18,6 +18,6 @@ fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
#[define_opaque(Two)] #[define_opaque(Two)]
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> { fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
(t, u, 42)
//~^ ERROR concrete type differs //~^ ERROR concrete type differs
(t, u, 42)
} }

Some files were not shown because too many files have changed in this diff Show more