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:
commit
17ffbc81a3
136 changed files with 1069 additions and 993 deletions
|
@ -162,13 +162,6 @@ borrowck_opaque_type_lifetime_mismatch =
|
|||
.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
|
||||
|
||||
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 =
|
||||
variable {$is_partial ->
|
||||
[true] partially moved
|
||||
|
|
|
@ -35,7 +35,7 @@ use rustc_infer::infer::{
|
|||
};
|
||||
use rustc_middle::mir::*;
|
||||
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_mir_dataflow::impls::{
|
||||
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 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 move_data = MoveData::gather_moves(body, tcx, |_| true);
|
||||
|
@ -431,7 +425,12 @@ pub(crate) struct BorrowckInferCtxt<'tcx> {
|
|||
|
||||
impl<'tcx> BorrowckInferCtxt<'tcx> {
|
||||
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);
|
||||
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
|
||||
}
|
||||
|
@ -478,29 +477,6 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
|
|||
|
||||
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> {
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
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_infer::infer::{InferCtxt, NllRegionVariableOrigin};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
|
||||
TypeVisitableExt, TypingMode, fold_regions,
|
||||
self, DefiningScopeKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
|
||||
TypeVisitableExt, fold_regions,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
use crate::opaque_types::ConcreteOpaqueTypes;
|
||||
use crate::session_diagnostics::{LifetimeMismatchOpaqueParam, NonGenericOpaqueTypeParam};
|
||||
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
|
||||
use crate::universal_regions::RegionClassification;
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
@ -272,14 +267,21 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
return Ty::new_error(self.tcx, e);
|
||||
}
|
||||
|
||||
if let Err(guar) =
|
||||
check_opaque_type_parameter_valid(self, opaque_type_key, instantiated_ty.span)
|
||||
{
|
||||
if let Err(guar) = check_opaque_type_parameter_valid(
|
||||
self,
|
||||
opaque_type_key,
|
||||
instantiated_ty.span,
|
||||
DefiningScopeKind::MirBorrowck,
|
||||
) {
|
||||
return Ty::new_error(self.tcx, guar);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if let Err(e) = definition_ty.error_reported() {
|
||||
|
@ -289,156 +291,3 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,17 +294,6 @@ pub(crate) struct MoveBorrow<'a> {
|
|||
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)]
|
||||
#[diag(borrowck_opaque_type_lifetime_mismatch)]
|
||||
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {
|
||||
|
|
|
@ -61,6 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
*providers = Providers {
|
||||
type_of: type_of::type_of,
|
||||
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,
|
||||
item_bounds: item_bounds::item_bounds,
|
||||
explicit_item_bounds: item_bounds::explicit_item_bounds,
|
||||
|
|
|
@ -7,7 +7,9 @@ use rustc_hir::{self as hir, AmbigArg, HirId};
|
|||
use rustc_middle::query::plumbing::CyclePlaceholder;
|
||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||
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_span::{DUMMY_SP, Ident, Span};
|
||||
|
||||
|
@ -324,10 +326,18 @@ pub(super) fn type_of_opaque(
|
|||
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 {
|
||||
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, .. } => {
|
||||
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`.
|
||||
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"
|
||||
);
|
||||
}
|
||||
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 {
|
||||
|
@ -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>(
|
||||
cx: &dyn HirTyLowerer<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
|
|
|
@ -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_middle::bug;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_middle::ty::{self, DefiningScopeKind, Ty, TyCtxt, TypeVisitableExt};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
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(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
opaque_types_from: DefiningScopeKind,
|
||||
) -> Ty<'_> {
|
||||
let mut parent_def_id = def_id;
|
||||
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:?}"),
|
||||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
// 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
|
||||
} else {
|
||||
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
|
||||
let guar = tcx.dcx().emit_err(UnconstrainedOpaqueType {
|
||||
span: tcx.def_span(def_id),
|
||||
name: tcx.item_ident(parent_def_id.to_def_id()),
|
||||
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> { .. }
|
||||
/// ```
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
||||
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
|
||||
pub(super) fn find_opaque_ty_constraints_for_tait(
|
||||
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);
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
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),
|
||||
name: tcx.item_ident(parent_def_id.to_def_id()),
|
||||
what: "crate",
|
||||
});
|
||||
Ty::new_error(tcx, reported)
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,22 +108,44 @@ struct TaitConstraintLocator<'tcx> {
|
|||
/// type).
|
||||
found: Option<ty::OpaqueHiddenType<'tcx>>,
|
||||
|
||||
/// In the presence of dead code, typeck may figure out a hidden type
|
||||
/// 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>>,
|
||||
opaque_types_from: DefiningScopeKind,
|
||||
}
|
||||
|
||||
impl TaitConstraintLocator<'_> {
|
||||
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));
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn check(&mut self, item_def_id: LocalDefId) {
|
||||
// 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");
|
||||
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.
|
||||
if !opaque_types_defined_by.contains(&self.def_id) {
|
||||
debug!("no constraint: no opaque types defined");
|
||||
|
@ -152,7 +156,7 @@ impl TaitConstraintLocator<'_> {
|
|||
// "non-defining use" errors for them.
|
||||
// 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.
|
||||
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!(
|
||||
!matches!(hir_node, Node::ForeignItem(..)),
|
||||
"foreign items cannot constrain opaque types",
|
||||
|
@ -164,88 +168,39 @@ impl TaitConstraintLocator<'_> {
|
|||
hir_sig.decl.output.span(),
|
||||
"inferring return types and opaque types do not mix well",
|
||||
);
|
||||
self.found =
|
||||
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
|
||||
self.found = Some(ty::OpaqueHiddenType::new_error(tcx, guar));
|
||||
return;
|
||||
}
|
||||
|
||||
// Calling `mir_borrowck` can lead to cycle errors through
|
||||
// const-checking, avoid calling it if we don't have to.
|
||||
// ```rust
|
||||
// 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 {
|
||||
self.found =
|
||||
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
match self.opaque_types_from {
|
||||
DefiningScopeKind::HirTypeck => {
|
||||
let tables = tcx.typeck(item_def_id);
|
||||
if let Some(guar) = tables.tainted_by_errors {
|
||||
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
|
||||
} else if let Some(&hidden_type) = tables.concrete_opaque_types.get(&self.def_id) {
|
||||
self.insert_found(hidden_type);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
self.found = Some(concrete_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -287,126 +242,42 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
owner_def_id: LocalDefId,
|
||||
opaque_types_from: DefiningScopeKind,
|
||||
) -> Ty<'tcx> {
|
||||
let tables = tcx.typeck(owner_def_id);
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
match opaque_types_from {
|
||||
DefiningScopeKind::HirTypeck => {
|
||||
let tables = tcx.typeck(owner_def_id);
|
||||
if let Some(guar) = tables.tainted_by_errors {
|
||||
Ty::new_error(tcx, guar)
|
||||
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
|
||||
hidden_ty.ty
|
||||
} else {
|
||||
hir_opaque_ty = Some(concrete_type);
|
||||
// FIXME(-Znext-solver): This should not be necessary and we should
|
||||
// instead rely on inference variable fallback inside of typeck itself.
|
||||
|
||||
// We failed to resolve the opaque type or it
|
||||
// resolves to itself. We interpret this as the
|
||||
// no values of the hidden type ever being constructed,
|
||||
// so we can just make the hidden type be `!`.
|
||||
// For backwards compatibility reasons, we fall back to
|
||||
// `()` until we the diverging default is changed.
|
||||
Ty::new_diverging_default(tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
} else {
|
||||
// Fall back to the RPIT we inferred during HIR typeck
|
||||
if let Some(hir_opaque_ty) = hir_opaque_ty {
|
||||
hir_opaque_ty.ty
|
||||
} else {
|
||||
// We failed to resolve the opaque type or it
|
||||
// resolves to itself. We interpret this as the
|
||||
// no values of the hidden type ever being constructed,
|
||||
// so we can just make the hidden type be `!`.
|
||||
// For backwards compatibility reasons, we fall back to
|
||||
// `()` until we the diverging default is changed.
|
||||
Ty::new_diverging_default(tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RpitConstraintChecker<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
/// def_id of the opaque type whose defining uses are being checked
|
||||
def_id: LocalDefId,
|
||||
|
||||
found: ty::OpaqueHiddenType<'tcx>,
|
||||
}
|
||||
|
||||
impl RpitConstraintChecker<'_> {
|
||||
#[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();
|
||||
DefiningScopeKind::MirBorrowck => {
|
||||
let borrowck_result = tcx.mir_borrowck(owner_def_id);
|
||||
if let Some(guar) = borrowck_result.tainted_by_errors {
|
||||
Ty::new_error(tcx, guar)
|
||||
} else if let Some(hidden_ty) = borrowck_result.concrete_opaque_types.get(&def_id) {
|
||||
hidden_ty.ty
|
||||
} else {
|
||||
let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
|
||||
if let Err(guar) = hir_ty.error_reported() {
|
||||
Ty::new_error(tcx, guar)
|
||||
} else {
|
||||
hir_ty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@ use rustc_middle::span_bug;
|
|||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
|
||||
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_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 tracing::{debug, instrument};
|
||||
|
||||
|
@ -555,6 +557,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
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
|
||||
// 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
|
||||
// are equal modulo regions.
|
||||
if let Some(last_opaque_ty) =
|
||||
self.typeck_results.concrete_opaque_types.insert(opaque_type_key, hidden_type)
|
||||
&& last_opaque_ty.ty != hidden_type.ty
|
||||
if let Err(guar) = check_opaque_type_parameter_valid(
|
||||
&self.fcx,
|
||||
opaque_type_key,
|
||||
hidden_type.span,
|
||||
DefiningScopeKind::HirTypeck,
|
||||
) {
|
||||
self.typeck_results
|
||||
.concrete_opaque_types
|
||||
.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)
|
||||
{
|
||||
assert!(!self.fcx.next_trait_solver());
|
||||
if let Ok(d) = hidden_type.build_mismatch_error(&last_opaque_ty, self.tcx()) {
|
||||
d.emit();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -967,7 +967,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
|
||||
debug_assert!(!self.next_trait_solver());
|
||||
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))
|
||||
}
|
||||
// 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
|
||||
// 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.
|
||||
ty::TypingMode::Analysis { defining_opaque_types: _ } => {
|
||||
ty::TypingMode::Analysis { defining_opaque_types: _ }
|
||||
| ty::TypingMode::Borrowck { defining_opaque_types: _ } => {
|
||||
TypingMode::non_body_analysis()
|
||||
}
|
||||
mode @ (ty::TypingMode::Coherence
|
||||
|
|
|
@ -12,7 +12,7 @@ use rustc_middle::ty::{
|
|||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::DefineOpaqueTypes;
|
||||
use super::{DefineOpaqueTypes, RegionVariableOrigin};
|
||||
use crate::errors::OpaqueHiddenTypeDiag;
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::{self, Obligation, PredicateObligations};
|
||||
|
@ -221,6 +221,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
hidden_ty: Ty<'tcx>,
|
||||
goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
// Ideally, we'd get the span where *this specific `ty` came
|
||||
// from*, but right now we just use the span from the overall
|
||||
// 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
|
||||
// force ambiguity unless the hidden type is known to not implement
|
||||
// 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 { .. } => {
|
||||
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) => {
|
||||
bug!("insert hidden type in {mode:?}")
|
||||
}
|
||||
|
|
|
@ -267,6 +267,8 @@ rustc_queries! {
|
|||
///
|
||||
/// 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.
|
||||
/// This is used to improve the error message in cases where revealing the hidden type
|
||||
/// for auto-trait leakage cycles.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -278,6 +280,12 @@ rustc_queries! {
|
|||
}
|
||||
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.
|
||||
///
|
||||
|
|
|
@ -206,6 +206,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
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>;
|
||||
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
|
||||
}
|
||||
|
||||
#[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 {
|
||||
self.opt_rpitit_info(def_id).is_some()
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ use rustc_serialize::{Decodable, Encodable};
|
|||
use rustc_session::lint::LintBuffer;
|
||||
pub use rustc_session::lint::RegisteredTools;
|
||||
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::*;
|
||||
use tracing::{debug, instrument};
|
||||
|
@ -782,7 +782,22 @@ pub struct OpaqueHiddenType<'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> {
|
||||
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(
|
||||
&self,
|
||||
other: &Self,
|
||||
|
@ -808,8 +823,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
|
|||
self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
// typeck errors have subpar spans for opaque types, so delay error reporting until borrowck.
|
||||
ignore_errors: bool,
|
||||
defining_scope_kind: DefiningScopeKind,
|
||||
) -> Self {
|
||||
let OpaqueTypeKey { def_id, args } = opaque_type_key;
|
||||
|
||||
|
@ -828,10 +842,19 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
|
|||
let map = args.iter().zip(id_args).collect();
|
||||
debug!("map = {:#?}", map);
|
||||
|
||||
// Convert the type from the function into a type valid outside
|
||||
// the function, by replacing invalid regions with 'static,
|
||||
// after producing an error for each of them.
|
||||
self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors))
|
||||
// Convert the type from the function into a type valid outside by mapping generic
|
||||
// parameters to into the context of the opaque.
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,6 @@ pub(super) struct ReverseMapper<'tcx> {
|
|||
/// for an explanation of this field.
|
||||
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: Span,
|
||||
}
|
||||
|
@ -35,9 +29,8 @@ impl<'tcx> ReverseMapper<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
|
||||
span: Span,
|
||||
ignore_errors: bool,
|
||||
) -> 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> {
|
||||
|
@ -176,20 +169,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
|
|||
Some(u) => panic!("type mapped to unexpected kind: {u:?}"),
|
||||
None => {
|
||||
debug!(?param, ?self.map);
|
||||
if !self.ignore_errors {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
self.span,
|
||||
format!(
|
||||
"type parameter `{ty}` is part of concrete type but not \
|
||||
let guar = self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
self.span,
|
||||
format!(
|
||||
"type parameter `{ty}` is part of concrete type but not \
|
||||
used in parameter list for the `impl Trait` type alias"
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
Ty::new_misc_error(self.tcx)
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
Ty::new_error(self.tcx, guar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,8 +208,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
|
|||
ct: ct.to_string(),
|
||||
span: self.span,
|
||||
})
|
||||
.emit_unless(self.ignore_errors);
|
||||
|
||||
.emit();
|
||||
ty::Const::new_error(self.tcx, guar)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ pub struct TypeckResults<'tcx> {
|
|||
/// 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
|
||||
/// (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;
|
||||
/// see `MinCaptureInformationMap` for more details.
|
||||
|
|
|
@ -330,6 +330,7 @@ where
|
|||
// During analysis, opaques are rigid unless they may be defined by
|
||||
// the current body.
|
||||
TypingMode::Analysis { defining_opaque_types: non_rigid_opaques }
|
||||
| TypingMode::Borrowck { defining_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))
|
||||
}
|
||||
|
|
|
@ -96,6 +96,42 @@ where
|
|||
);
|
||||
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 } => {
|
||||
let Some(def_id) = opaque_ty
|
||||
.def_id
|
||||
|
|
|
@ -62,6 +62,7 @@ where
|
|||
response_no_constraints(cx, input, Certainty::overflow(false))
|
||||
}
|
||||
TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis => Err(NoSolution),
|
||||
},
|
||||
|
|
|
@ -72,6 +72,7 @@ where
|
|||
(ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
|
||||
TypingMode::Coherence => Certainty::AMBIGUOUS,
|
||||
TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis => return Err(NoSolution),
|
||||
},
|
||||
|
|
|
@ -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
|
||||
/// know it.
|
||||
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.
|
||||
pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
|
||||
|
|
|
@ -2555,6 +2555,9 @@ written to standard error output)"),
|
|||
"in diagnostics, use heuristics to shorten paths referring to items"),
|
||||
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"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")]
|
||||
ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"),
|
||||
|
|
|
@ -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_try_compat = `?` operator has incompatible types
|
||||
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
|
||||
.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_content = lifetime of reference outlives lifetime of borrowed content...
|
||||
|
|
|
@ -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_macros::{Diagnostic, Subdiagnostic};
|
||||
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 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,
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
pub mod error_reporting;
|
||||
pub mod errors;
|
||||
pub mod infer;
|
||||
pub mod opaque_types;
|
||||
pub mod regions;
|
||||
pub mod solve;
|
||||
pub mod traits;
|
||||
|
|
182
compiler/rustc_trait_selection/src/opaque_types.rs
Normal file
182
compiler/rustc_trait_selection/src/opaque_types.rs
Normal 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
|
||||
}
|
||||
}
|
|
@ -195,6 +195,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
match self.typing_mode() {
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => false,
|
||||
TypingMode::PostAnalysis => {
|
||||
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
|
||||
|
|
|
@ -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
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
|
||||
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
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
|
||||
TypingMode::PostAnalysis => {
|
||||
let recursion_limit = self.cx().recursion_limit();
|
||||
|
|
|
@ -952,6 +952,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
match selcx.infcx.typing_mode() {
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => {
|
||||
debug!(
|
||||
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
|
||||
|
|
|
@ -216,6 +216,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
match self.infcx.typing_mode() {
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => ty.try_super_fold_with(self)?,
|
||||
|
||||
TypingMode::PostAnalysis => {
|
||||
|
|
|
@ -1446,6 +1446,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match self.infcx.typing_mode() {
|
||||
TypingMode::Coherence => {}
|
||||
TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| 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.
|
||||
// This is likely fixed by better caching in general in the new solver.
|
||||
// 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()
|
||||
}
|
||||
// The hidden types of `defined_opaque_types` is not local to the current
|
||||
|
|
|
@ -149,6 +149,7 @@ fn resolve_associated_item<'tcx>(
|
|||
match typing_env.typing_mode {
|
||||
ty::TypingMode::Coherence
|
||||
| ty::TypingMode::Analysis { .. }
|
||||
| ty::TypingMode::Borrowck { .. }
|
||||
| ty::TypingMode::PostBorrowckAnalysis { .. } => false,
|
||||
ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
|
||||
}
|
||||
|
|
|
@ -66,6 +66,14 @@ pub enum TypingMode<I: Interner> {
|
|||
/// }
|
||||
/// ```
|
||||
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
|
||||
/// 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) }
|
||||
}
|
||||
|
||||
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> {
|
||||
TypingMode::PostBorrowckAnalysis {
|
||||
defined_opaque_types: cx.opaque_types_defined_by(body_def_id),
|
||||
|
|
|
@ -149,6 +149,8 @@ pub trait Interner:
|
|||
) -> Option<Self::VariancesOf>;
|
||||
|
||||
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>;
|
||||
fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef;
|
||||
|
|
|
@ -137,6 +137,7 @@ where
|
|||
Ok(a)
|
||||
}
|
||||
TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b),
|
||||
}
|
||||
|
|
|
@ -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() {}
|
|
@ -1,6 +0,0 @@
|
|||
//@ known-bug: #137751
|
||||
//@ compile-flags: --edition=2021 -Znext-solver=globally
|
||||
async fn test() {
|
||||
Box::pin(test()).await;
|
||||
}
|
||||
fn main() {}
|
|
@ -35,11 +35,11 @@ note: ...which requires type-checking `foo::{closure#0}`...
|
|||
LL | move |_: ()| {
|
||||
| ^^^^^^^^^^^^
|
||||
= note: ...which again requires type-checking `foo`, completing the cycle
|
||||
note: cycle used when computing type of opaque `foo::{opaque#0}`
|
||||
--> $DIR/clone-rpit.rs:13:25
|
||||
note: cycle used when match-checking `foo`
|
||||
--> $DIR/clone-rpit.rs:13:1
|
||||
|
|
||||
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
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
|
@ -15,8 +15,8 @@ pub trait Trait2 {
|
|||
|
||||
impl<'c, S: Trait2> Trait2 for &'c mut S {
|
||||
type FooFuture<'a> = impl Trait1;
|
||||
//~^ ERROR unconstrained opaque type
|
||||
fn foo<'a>() -> Self::FooFuture<'a> {
|
||||
//~^ ERROR item does not constrain `<&'c mut S as Trait2>::FooFuture::{opaque#0}`
|
||||
Struct(unimplemented!())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ pub trait Trait2 {
|
|||
}
|
||||
|
||||
type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
|
||||
//~^ ERROR unconstrained opaque type
|
||||
|
||||
impl<'c, S: Trait2> Trait2 for &'c mut S {
|
||||
type FooFuture<'a> = Helper<'c, 'a, S>;
|
||||
#[define_opaque(Helper)]
|
||||
fn foo<'a>() -> Self::FooFuture<'a> {
|
||||
//~^ ERROR item does not constrain `Helper::{opaque#0}`
|
||||
Struct(unimplemented!())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
--> $DIR/norm-before-method-resolution-opaque-type.rs:23:13
|
||||
--> $DIR/norm-before-method-resolution-opaque-type.rs:22:13
|
||||
|
|
||||
LL | let x = *x;
|
||||
| ^^ 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;
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0507`.
|
||||
|
|
|
@ -15,7 +15,6 @@ type Foo = impl Sized;
|
|||
|
||||
#[define_opaque(Foo)]
|
||||
fn weird_bound<X>(x: &<X as Trait<'static>>::Out<Foo>) -> X
|
||||
//[old]~^ ERROR: item does not constrain
|
||||
where
|
||||
for<'a> X: Trait<'a>,
|
||||
for<'a> <X as Trait<'a>>::Out<()>: Copy,
|
||||
|
|
|
@ -13,6 +13,7 @@ impl<S: Default> Bar for S {
|
|||
//~^ ERROR impl has stricter requirements than trait
|
||||
//~| 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 type parameter `T` is part of concrete type
|
||||
(S::default(), T::default())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,13 @@ help: consider further restricting type parameter `T` with trait `Copy`
|
|||
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.
|
||||
For more information about an error, try `rustc --explain E0276`.
|
||||
|
|
|
@ -11,9 +11,9 @@ pub trait Bar {
|
|||
impl<S> Bar for S {
|
||||
type E = impl std::marker::Send;
|
||||
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
|
||||
async {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
--> $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
|
||||
--> $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`
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ impl<S> Bar for S {
|
|||
type E = impl std::marker::Copy;
|
||||
fn foo<T>() -> Self::E {
|
||||
//~^ ERROR : Copy` is not satisfied [E0277]
|
||||
//~| ERROR type parameter `T` is part of concrete type
|
||||
async {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
LL | fn foo<T>() -> Self::E {
|
||||
| ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:16:9: 16:14}`
|
||||
LL |
|
||||
| ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}`
|
||||
...
|
||||
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`.
|
||||
|
|
|
@ -10,8 +10,8 @@ impl<S> Bar for S {
|
|||
type E = impl Copy;
|
||||
|
||||
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
|
||||
|| ()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
--> $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
|
||||
|
||||
|
|
|
@ -7,8 +7,7 @@ fn main() {
|
|||
fn test<T: Display>(t: T, recurse: bool) -> impl Display {
|
||||
let f = || {
|
||||
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}");
|
||||
};
|
||||
if recurse {
|
||||
|
|
|
@ -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`
|
||||
--> $DIR/issue-99073-2.rs:9:22
|
||||
|
|
||||
|
@ -19,6 +7,6 @@ LL | let f = || {
|
|||
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`.
|
||||
|
|
|
@ -4,6 +4,5 @@ fn main() {
|
|||
|
||||
fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
|
||||
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`
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
--> $DIR/issue-99073.rs:6:11
|
||||
--> $DIR/issue-99073.rs:6:13
|
||||
|
|
||||
LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
|
||||
| - this generic parameter must be used with a generic type parameter
|
||||
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`.
|
||||
|
|
17
tests/ui/impl-trait/issues/fuzzer-ice-issue-112201.rs
Normal file
17
tests/ui/impl-trait/issues/fuzzer-ice-issue-112201.rs
Normal 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() {}
|
18
tests/ui/impl-trait/issues/fuzzer-ice-issue-112201.stderr
Normal file
18
tests/ui/impl-trait/issues/fuzzer-ice-issue-112201.stderr
Normal 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`.
|
|
@ -29,7 +29,6 @@ where
|
|||
F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f,
|
||||
{
|
||||
f
|
||||
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||
}
|
||||
|
||||
impl Context {
|
||||
|
@ -39,7 +38,6 @@ impl Context {
|
|||
&self,
|
||||
f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>,
|
||||
) -> TransactionResult<O> {
|
||||
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||
let mut conn = Connection {};
|
||||
let mut transaction = TestTransaction { conn: &mut conn };
|
||||
f(&mut transaction).await
|
||||
|
|
|
@ -12,7 +12,7 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResu
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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>(
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -24,30 +24,5 @@ note: this opaque type is supposed to be constrained
|
|||
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0792]: expected generic lifetime parameter, found `'_`
|
||||
--> $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: aborting due to 2 previous errors
|
||||
|
||||
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`.
|
||||
|
|
|
@ -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`.
|
17
tests/ui/impl-trait/non-defining-uses/as-projection-term.rs
Normal file
17
tests/ui/impl-trait/non-defining-uses/as-projection-term.rs
Normal 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() {}
|
|
@ -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
|
||||
--> $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
|
||||
= 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
|
||||
|
||||
For more information about this error, try `rustc --explain E0792`.
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use std::convert::identity;
|
||||
|
||||
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 _ = || {
|
||||
let _ = identity::<&'a ()>(test(false));
|
||||
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||
//~^ ERROR concrete type differs from previous defining opaque type use
|
||||
};
|
||||
loop {}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
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
|
||||
|
|
||||
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 `'_`
|
||||
--> $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 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0792`.
|
||||
|
|
|
@ -6,8 +6,7 @@ fn foo<T>() -> impl Sized {
|
|||
|
||||
fn bar<T>(val: T) -> impl Sized {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +1,19 @@
|
|||
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 {
|
||||
| - this generic parameter must be used with a generic type parameter
|
||||
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`
|
||||
--> $DIR/non-defining-use.rs:8:12
|
||||
--> $DIR/non-defining-use.rs:8:17
|
||||
|
|
||||
LL | fn bar<T>(val: T) -> impl Sized {
|
||||
| - this generic parameter must be used with a generic type parameter
|
||||
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`.
|
||||
|
|
|
@ -9,6 +9,31 @@ note: ...which requires computing type of opaque `foo::{opaque#0}`...
|
|||
|
|
||||
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`...
|
||||
--> $DIR/in-defining-scope.rs:6:1
|
||||
|
|
||||
|
|
|
@ -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
|
||||
--> $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)
|
||||
| ^ 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;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@ trait Foo {}
|
|||
|
||||
#[define_opaque(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)
|
||||
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type
|
||||
}
|
||||
|
|
|
@ -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
|
||||
//@ check-pass
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
|
|
@ -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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -17,38 +17,37 @@ mod ex0 {
|
|||
}
|
||||
mod ex1 {
|
||||
type Tait1 = impl Sized;
|
||||
//[current]~^ ERROR unconstrained opaque type
|
||||
#[define_opaque(Tait1)]
|
||||
fn foo(x: Tait1) -> impl Sized {
|
||||
//[current]~^ ERROR item does not constrain `ex1::Tait1::{opaque#0}`
|
||||
let () = x;
|
||||
}
|
||||
}
|
||||
|
||||
mod ex2 {
|
||||
type Tait1 = impl Sized;
|
||||
//[current]~^ ERROR unconstrained opaque type
|
||||
type Tait2 = impl Sized;
|
||||
#[define_opaque(Tait1, Tait2)]
|
||||
fn foo(x: Tait1) -> Tait2 {
|
||||
//[current]~^ ERROR item does not constrain `ex2::Tait1::{opaque#0}`
|
||||
let () = x;
|
||||
}
|
||||
}
|
||||
|
||||
mod ex3 {
|
||||
type Tait1 = impl Sized;
|
||||
//[current]~^ ERROR unconstrained opaque type
|
||||
trait Something<T> {}
|
||||
impl<T, U> Something<U> for T {}
|
||||
type Tait2 = impl Something<Tait1>;
|
||||
#[define_opaque(Tait1, Tait2)]
|
||||
fn foo(x: Tait1) -> Tait2 {
|
||||
//[current]~^ ERROR item does not constrain `ex3::Tait1::{opaque#0}`
|
||||
let () = x;
|
||||
}
|
||||
}
|
||||
|
||||
mod ex4 {
|
||||
type Tait1 = impl Sized;
|
||||
//[current]~^ ERROR unconstrained opaque type
|
||||
trait Trait<U> {
|
||||
type Assoc;
|
||||
}
|
||||
|
@ -63,6 +62,7 @@ mod ex4 {
|
|||
type Tait2 = impl Trait<(), Assoc = impl Trait<Tait1>>;
|
||||
#[define_opaque(Tait1, Tait2)]
|
||||
fn foo(x: Tait1) -> Tait2 {
|
||||
//[current]~^ ERROR item does not constrain `ex4::Tait1::{opaque#0}`
|
||||
let () = x;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {}
|
|
@ -12,7 +12,6 @@ pub enum UninhabitedVariants {
|
|||
|
||||
#[define_opaque(Alias)]
|
||||
fn uwu(x: UninhabitedVariants) {
|
||||
//~^ ERROR item does not constrain
|
||||
match x {}
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
}
|
||||
|
|
|
@ -26,21 +26,8 @@ help: add missing generic argument
|
|||
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
|
||||
--> $DIR/bad-tait-no-substs.rs:16:11
|
||||
--> $DIR/bad-tait-no-substs.rs:15:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^ pattern `UninhabitedVariants::Tuple(_)` not covered
|
||||
|
@ -60,7 +47,7 @@ LL + UninhabitedVariants::Tuple(_) => todo!(),
|
|||
LL ~ }
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0004, E0106, E0107.
|
||||
For more information about an error, try `rustc --explain E0004`.
|
||||
|
|
|
@ -14,6 +14,6 @@ impl<W> Trait<W> for () {}
|
|||
|
||||
#[define_opaque(Foo)]
|
||||
fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
|
||||
()
|
||||
//~^ ERROR expected generic type parameter, found `<T as TraitWithAssoc>::Assoc`
|
||||
()
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
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>;
|
||||
| - 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
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> {
|
|||
|
||||
#[define_opaque(Opaque)]
|
||||
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>>
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,6 @@ fn foo() -> Foo {
|
|||
|
||||
#[define_opaque(Foo)]
|
||||
fn bar() -> Foo {
|
||||
//~^ ERROR concrete type differs
|
||||
42i32
|
||||
//~^ ERROR concrete type differs from previous
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
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
|
||||
| ^^^^^ expected `&'static str`, got `i32`
|
||||
LL | fn bar() -> Foo {
|
||||
| ^^^ expected `&str`, got `i32`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ fn foo<'a, 'b>() -> Tait<'a> {
|
|||
}
|
||||
let x: Tait<'a> = ();
|
||||
x
|
||||
//~^ ERROR concrete type differs from previous defining opaque type use
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -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
|
||||
--> $DIR/different_defining_uses_never_type-2.rs:9:31
|
||||
|
|
||||
|
@ -17,10 +5,10 @@ LL | let y: Tait<'b> = 1i32;
|
|||
| ^^^^ expected `()`, got `i32`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ LL | let y: Tait<U> = 1i32;
|
|||
| ^^^^ expected `()`, got `i32`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ error: concrete type differs from previous defining opaque type use
|
|||
--> $DIR/different_defining_uses_never_type.rs:14:13
|
||||
|
|
||||
LL | fn bar() -> Foo {
|
||||
| ^^^ expected `&'static str`, got `()`
|
||||
| ^^^ expected `&str`, got `()`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ LL | fn two() -> Tait { Two::<()>(todo!()) }
|
|||
| ^^^^ expected `One`, got `Two<()>`
|
||||
|
|
||||
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 }
|
||||
| ^^^
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -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<()> {
|
||||
//~^ ERROR item does not constrain
|
||||
StatefulWidget(build)
|
||||
//~^ ERROR expected generic lifetime parameter, found `'a`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -24,17 +24,8 @@ note: this opaque type is supposed to be constrained
|
|||
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
|
||||
--> $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 ()>;
|
||||
| ------------------- the expected opaque type
|
||||
|
@ -45,7 +36,6 @@ LL | new_stateful_widget(|_| ()).make_state();
|
|||
= note: expected opaque type `StateWidget<'_>`
|
||||
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 an error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
|
@ -11,6 +11,6 @@ fn my_iter<T>(t: T) -> MyIter<T> {
|
|||
|
||||
#[define_opaque(MyIter)]
|
||||
fn my_iter2<T>(t: T) -> MyIter<T> {
|
||||
Some(t).into_iter()
|
||||
//~^ ERROR concrete type differs from previous
|
||||
Some(t).into_iter()
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
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()
|
||||
| ^^^^^^^^^^^^^^^^^^^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
|
||||
LL | fn my_iter2<T>(t: T) -> MyIter<T> {
|
||||
| ^^^^^^^^^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ type TwoConsts<const X: usize, const Y: usize> = impl Debug;
|
|||
|
||||
#[define_opaque(TwoTys)]
|
||||
fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
|
||||
t
|
||||
//~^ ERROR non-defining opaque type use in defining scope
|
||||
t
|
||||
}
|
||||
|
||||
#[define_opaque(TwoLifetimes)]
|
||||
|
@ -32,6 +32,6 @@ fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
|
|||
|
||||
#[define_opaque(TwoConsts)]
|
||||
fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> {
|
||||
t
|
||||
//~^ ERROR non-defining opaque type use in defining scope
|
||||
t
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $DIR/generic_duplicate_param_use.rs:19:16
|
||||
|
|
|
@ -14,6 +14,6 @@ fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
|
|||
|
||||
#[define_opaque(Two)]
|
||||
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
|
||||
u
|
||||
//~^ ERROR concrete type differs
|
||||
u
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
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
|
||||
| ^ expected `T`, got `U`
|
||||
LL | fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
|
||||
| ^^^^^^^^^ expected `T`, got `U`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -14,6 +14,6 @@ fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
|||
|
||||
#[define_opaque(Two)]
|
||||
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
(u, t)
|
||||
//~^ ERROR concrete type differs
|
||||
(u, t)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
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)
|
||||
| ^^^^^^ expected `(T, U)`, got `(U, T)`
|
||||
LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
| ^^^^^^^^^ expected `(T, U)`, got `(U, T)`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -14,6 +14,6 @@ fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
|||
|
||||
#[define_opaque(Two)]
|
||||
fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
(u, t)
|
||||
//~^ ERROR concrete type differs
|
||||
(u, t)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
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)
|
||||
| ^^^^^^ expected `(T, T)`, got `(U, T)`
|
||||
LL | fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
| ^^^^^^^^^ expected `(T, T)`, got `(U, T)`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -13,6 +13,6 @@ fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
|
|||
|
||||
#[define_opaque(Two)]
|
||||
fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
|
||||
(u, 4u32)
|
||||
//~^ concrete type differs
|
||||
(u, 4u32)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
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)
|
||||
| ^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
|
||||
LL | fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
|
||||
| ^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -18,6 +18,6 @@ fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
|
|||
|
||||
#[define_opaque(Two)]
|
||||
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
(t, u, 42)
|
||||
//~^ ERROR concrete type differs
|
||||
(t, u, 42)
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue