Auto merge of #145711 - lcnr:non-defining-uses-hir-typeck, r=BoxyUwU
Support non-defining uses in HIR typeck This changes the impl of `NormalizesTo` for opaque types to be structural during HIR typeck. The previous impl equated region variables of the opaque type key with existing entries which can result in spurious leak check errors and also results in mismatches with MIR borrowck, theoretically causing ICE. The approach is very similar to rust-lang/rust#145244 in MIR typeck: - we collect all uses of opaque types during HIR typeck - before writeback, we search for *defining uses* - the opaque type key has fully universal generic args modulo regions - the hidden type has no infer vars - we use these defining uses to compute the concrete type for the opaque and map it to the definition site - we use this concrete type to check the type of all uses of opaques during HIR typeck. This also constrains infer vars in non-defining uses Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/135, fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/49. r? `@BoxyUwU`
This commit is contained in:
commit
d327d651e2
35 changed files with 585 additions and 398 deletions
|
|
@ -17,7 +17,7 @@ use rustc_middle::ty::{
|
|||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::{
|
||||
InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
|
||||
NonDefiningUseReason, opaque_type_has_defining_use_args,
|
||||
};
|
||||
use rustc_trait_selection::solve::NoSolution;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
|
|
@ -42,7 +42,7 @@ use region_ctxt::RegionCtxt;
|
|||
/// if there are no `RegionErrors`. If there are region errors, it's likely
|
||||
/// that errors here are caused by them and don't need to be handled separately.
|
||||
pub(crate) enum DeferredOpaqueTypeError<'tcx> {
|
||||
InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>),
|
||||
InvalidOpaqueTypeArgs(NonDefiningUseReason<'tcx>),
|
||||
LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>),
|
||||
UnexpectedHiddenRegion {
|
||||
/// The opaque type.
|
||||
|
|
@ -238,7 +238,7 @@ fn collect_defining_uses<'tcx>(
|
|||
let non_nll_opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |r| {
|
||||
nll_var_to_universal_region(&rcx, r.as_var()).unwrap_or(r)
|
||||
});
|
||||
if let Err(err) = check_opaque_type_parameter_valid(
|
||||
if let Err(err) = opaque_type_has_defining_use_args(
|
||||
infcx,
|
||||
non_nll_opaque_type_key,
|
||||
hidden_type.span,
|
||||
|
|
@ -248,11 +248,10 @@ fn collect_defining_uses<'tcx>(
|
|||
// with `TypingMode::Borrowck`.
|
||||
if infcx.tcx.use_typing_mode_borrowck() {
|
||||
match err {
|
||||
InvalidOpaqueTypeArgs::AlreadyReported(guar) => root_cx
|
||||
.add_concrete_opaque_type(
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(infcx.tcx, guar),
|
||||
),
|
||||
NonDefiningUseReason::Tainted(guar) => root_cx.add_concrete_opaque_type(
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(infcx.tcx, guar),
|
||||
),
|
||||
_ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"),
|
||||
}
|
||||
} else {
|
||||
|
|
@ -676,8 +675,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> {
|
||||
check_opaque_type_parameter_valid(
|
||||
) -> Result<Ty<'tcx>, NonDefiningUseReason<'tcx>> {
|
||||
opaque_type_has_defining_use_args(
|
||||
self,
|
||||
opaque_type_key,
|
||||
instantiated_ty.span,
|
||||
|
|
|
|||
|
|
@ -509,10 +509,6 @@ hir_analysis_supertrait_item_shadowee = item from `{$supertrait}` is shadowed by
|
|||
|
||||
hir_analysis_supertrait_item_shadowing = trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait
|
||||
|
||||
hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`
|
||||
.note = consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
|
||||
.opaque = this opaque type is supposed to be constrained
|
||||
|
||||
hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
|
||||
|
||||
hir_analysis_too_large_static = extern static is too large for the target architecture
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravi
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::{self, DefiningScopeKind, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_trait_selection::opaque_types::report_item_does_not_constrain_error;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
|
||||
use crate::errors::UnconstrainedOpaqueType;
|
||||
|
||||
/// Checks "defining uses" of opaque `impl Trait` in associated types.
|
||||
/// These can only be defined by associated items of the same trait.
|
||||
|
|
@ -127,14 +128,11 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
|
|||
}
|
||||
|
||||
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),
|
||||
});
|
||||
// We make sure that all opaque types get defined while
|
||||
// type checking the defining scope, so this error is unreachable
|
||||
// with the new solver.
|
||||
assert!(!self.tcx.next_trait_solver_globally());
|
||||
let guar = report_item_does_not_constrain_error(self.tcx, item_def_id, self.def_id, None);
|
||||
self.insert_found(ty::OpaqueHiddenType::new_error(self.tcx, guar));
|
||||
}
|
||||
|
||||
|
|
@ -252,9 +250,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
|
||||
hidden_ty.ty
|
||||
} else {
|
||||
// FIXME(-Znext-solver): This should not be necessary and we should
|
||||
// instead rely on inference variable fallback inside of typeck itself.
|
||||
|
||||
assert!(!tcx.next_trait_solver_globally());
|
||||
// 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,
|
||||
|
|
@ -273,6 +269,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
if let Err(guar) = hir_ty.error_reported() {
|
||||
Ty::new_error(tcx, guar)
|
||||
} else {
|
||||
assert!(!tcx.next_trait_solver_globally());
|
||||
hir_ty
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,17 +410,6 @@ pub(crate) struct UnconstrainedOpaqueType {
|
|||
pub what: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_tait_forward_compat2)]
|
||||
#[note]
|
||||
pub(crate) struct TaitForwardCompat2 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[note(hir_analysis_opaque)]
|
||||
pub opaque_type_span: Span,
|
||||
pub opaque_type: String,
|
||||
}
|
||||
|
||||
pub(crate) struct MissingTypeParams {
|
||||
pub span: Span,
|
||||
pub def_span: Span,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ mod coherence;
|
|||
mod collect;
|
||||
mod constrained_generic_params;
|
||||
mod delegation;
|
||||
mod errors;
|
||||
pub mod errors;
|
||||
pub mod hir_ty_lowering;
|
||||
pub mod hir_wf_check;
|
||||
mod impl_wf_check;
|
||||
|
|
|
|||
|
|
@ -247,6 +247,13 @@ fn typeck_with_inspect<'tcx>(
|
|||
|
||||
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
|
||||
|
||||
// We need to handle opaque types before emitting ambiguity errors as applying
|
||||
// defining uses may guide type inference.
|
||||
if fcx.next_trait_solver() {
|
||||
fcx.handle_opaque_type_uses_next();
|
||||
}
|
||||
|
||||
fcx.select_obligations_where_possible(|_| {});
|
||||
if let None = fcx.infcx.tainted_by_errors() {
|
||||
fcx.report_ambiguity_errors();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,218 @@
|
|||
use super::FnCtxt;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::ty::{
|
||||
self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, TypeVisitableExt,
|
||||
TypingMode,
|
||||
};
|
||||
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||
use rustc_trait_selection::opaque_types::{
|
||||
NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error,
|
||||
};
|
||||
use rustc_trait_selection::solve;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::FnCtxt;
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
/// This takes all the opaque type uses during HIR typeck. It first computes
|
||||
/// the concrete hidden type by iterating over all defining uses.
|
||||
///
|
||||
/// A use during HIR typeck is defining if all non-lifetime arguments are
|
||||
/// unique generic parameters and the hidden type does not reference any
|
||||
/// inference variables.
|
||||
///
|
||||
/// It then uses these defining uses to guide inference for all other uses.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn handle_opaque_type_uses_next(&mut self) {
|
||||
// We clone the opaques instead of stealing them here as they are still used for
|
||||
// normalization in the next generation trait solver.
|
||||
let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types();
|
||||
let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
|
||||
let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
|
||||
debug_assert_eq!(prev, None);
|
||||
for entry in &mut opaque_types {
|
||||
*entry = self.resolve_vars_if_possible(*entry);
|
||||
}
|
||||
debug!(?opaque_types);
|
||||
|
||||
self.compute_concrete_opaque_types(&opaque_types);
|
||||
self.apply_computed_concrete_opaque_types(&opaque_types);
|
||||
}
|
||||
}
|
||||
|
||||
enum UsageKind<'tcx> {
|
||||
None,
|
||||
NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>),
|
||||
UnconstrainedHiddenType(OpaqueHiddenType<'tcx>),
|
||||
HasDefiningUse,
|
||||
}
|
||||
|
||||
impl<'tcx> UsageKind<'tcx> {
|
||||
fn merge(&mut self, other: UsageKind<'tcx>) {
|
||||
match (&*self, &other) {
|
||||
(UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(),
|
||||
(UsageKind::None, _) => *self = other,
|
||||
// When mergining non-defining uses, prefer earlier ones. This means
|
||||
// the error happens as early as possible.
|
||||
(
|
||||
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
|
||||
UsageKind::NonDefiningUse(..),
|
||||
) => {}
|
||||
// When merging unconstrained hidden types, we prefer later ones. This is
|
||||
// used as in most cases, the defining use is the final return statement
|
||||
// of our function, and other uses with defining arguments are likely not
|
||||
// intended to be defining.
|
||||
(
|
||||
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
|
||||
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse,
|
||||
) => *self = other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
fn compute_concrete_opaque_types(
|
||||
&mut self,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
for def_id in defining_opaque_types_and_generators {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::OpaqueTy => {}
|
||||
DefKind::Closure => continue,
|
||||
_ => unreachable!("not opaque or generator: {def_id:?}"),
|
||||
}
|
||||
|
||||
let mut usage_kind = UsageKind::None;
|
||||
for &(opaque_type_key, hidden_type) in opaque_types {
|
||||
if opaque_type_key.def_id != def_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
|
||||
if let UsageKind::HasDefiningUse = usage_kind {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let guar = match usage_kind {
|
||||
UsageKind::None => {
|
||||
if let Some(guar) = self.tainted_by_errors() {
|
||||
guar
|
||||
} else {
|
||||
report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None)
|
||||
}
|
||||
}
|
||||
UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => {
|
||||
report_item_does_not_constrain_error(
|
||||
self.tcx,
|
||||
self.body_id,
|
||||
def_id,
|
||||
Some((opaque_type_key, hidden_type.span)),
|
||||
)
|
||||
}
|
||||
UsageKind::UnconstrainedHiddenType(hidden_type) => {
|
||||
let infer_var = hidden_type
|
||||
.ty
|
||||
.walk()
|
||||
.filter_map(ty::GenericArg::as_term)
|
||||
.find(|term| term.is_infer())
|
||||
.unwrap_or_else(|| hidden_type.ty.into());
|
||||
self.err_ctxt()
|
||||
.emit_inference_failure_err(
|
||||
self.body_id,
|
||||
hidden_type.span,
|
||||
infer_var,
|
||||
TypeAnnotationNeeded::E0282,
|
||||
false,
|
||||
)
|
||||
.emit()
|
||||
}
|
||||
UsageKind::HasDefiningUse => continue,
|
||||
};
|
||||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.concrete_opaque_types
|
||||
.insert(def_id, OpaqueHiddenType::new_error(tcx, guar));
|
||||
self.set_tainted_by_errors(guar);
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_opaque_type_use(
|
||||
&mut self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
hidden_type: OpaqueHiddenType<'tcx>,
|
||||
) -> UsageKind<'tcx> {
|
||||
if let Err(err) = opaque_type_has_defining_use_args(
|
||||
&self,
|
||||
opaque_type_key,
|
||||
hidden_type.span,
|
||||
DefiningScopeKind::HirTypeck,
|
||||
) {
|
||||
match err {
|
||||
NonDefiningUseReason::Tainted(guar) => {
|
||||
self.typeck_results.borrow_mut().concrete_opaque_types.insert(
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(self.tcx, guar),
|
||||
);
|
||||
return UsageKind::HasDefiningUse;
|
||||
}
|
||||
_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
|
||||
};
|
||||
}
|
||||
|
||||
// We ignore uses of the opaque if they have any inference variables
|
||||
// as this can frequently happen with recursive calls.
|
||||
//
|
||||
// See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
|
||||
if hidden_type.ty.has_non_region_infer() {
|
||||
return UsageKind::UnconstrainedHiddenType(hidden_type);
|
||||
}
|
||||
|
||||
let cause = ObligationCause::misc(hidden_type.span, self.body_id);
|
||||
let at = self.at(&cause, self.param_env);
|
||||
let hidden_type = match solve::deeply_normalize(at, hidden_type) {
|
||||
Ok(hidden_type) => hidden_type,
|
||||
Err(errors) => {
|
||||
let guar = self.err_ctxt().report_fulfillment_errors(errors);
|
||||
OpaqueHiddenType::new_error(self.tcx, guar)
|
||||
}
|
||||
};
|
||||
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
|
||||
opaque_type_key,
|
||||
self.tcx,
|
||||
DefiningScopeKind::HirTypeck,
|
||||
);
|
||||
|
||||
let prev = self
|
||||
.typeck_results
|
||||
.borrow_mut()
|
||||
.concrete_opaque_types
|
||||
.insert(opaque_type_key.def_id, hidden_type);
|
||||
assert!(prev.is_none());
|
||||
UsageKind::HasDefiningUse
|
||||
}
|
||||
|
||||
fn apply_computed_concrete_opaque_types(
|
||||
&mut self,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
for &(key, hidden_type) in opaque_types {
|
||||
let expected =
|
||||
*self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap();
|
||||
|
||||
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
|
||||
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
|
||||
}
|
||||
}
|
||||
|
||||
/// We may in theory add further uses of an opaque after cloning the opaque
|
||||
/// types storage during writeback when computing the defining uses.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use rustc_middle::ty::{
|
|||
};
|
||||
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::opaque_types::opaque_type_has_defining_use_args;
|
||||
use rustc_trait_selection::solve;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -546,8 +546,24 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_opaque_types_next(&mut self) {
|
||||
let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut();
|
||||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||
for hidden_ty in fcx_typeck_results.concrete_opaque_types.values() {
|
||||
assert!(!hidden_ty.has_infer());
|
||||
}
|
||||
|
||||
assert_eq!(self.typeck_results.concrete_opaque_types.len(), 0);
|
||||
self.typeck_results.concrete_opaque_types =
|
||||
mem::take(&mut fcx_typeck_results.concrete_opaque_types);
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_opaque_types(&mut self) {
|
||||
if self.fcx.next_trait_solver() {
|
||||
return self.visit_opaque_types_next();
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
@ -558,17 +574,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
for (opaque_type_key, hidden_type) in opaque_types {
|
||||
let hidden_type = self.resolve(hidden_type, &hidden_type.span);
|
||||
let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span);
|
||||
|
||||
if !self.fcx.next_trait_solver() {
|
||||
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
|
||||
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
|
||||
&& alias_ty.args == opaque_type_key.args
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
|
||||
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
|
||||
&& alias_ty.args == opaque_type_key.args
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Err(err) = check_opaque_type_parameter_valid(
|
||||
if let Err(err) = opaque_type_has_defining_use_args(
|
||||
&self.fcx,
|
||||
opaque_type_key,
|
||||
hidden_type.span,
|
||||
|
|
@ -923,6 +936,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, outer_exclusive_binder, new_err))]
|
||||
fn handle_term<T>(
|
||||
&mut self,
|
||||
value: T,
|
||||
|
|
|
|||
|
|
@ -829,14 +829,15 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
|
|||
// 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.
|
||||
// We erase regions when doing this during HIR typeck. We manually use `fold_regions`
|
||||
// here as we do not want to anonymize bound variables.
|
||||
let this = match defining_scope_kind {
|
||||
DefiningScopeKind::HirTypeck => tcx.erase_regions(self),
|
||||
DefiningScopeKind::HirTypeck => fold_regions(tcx, self, |_, _| tcx.lifetimes.re_erased),
|
||||
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));
|
||||
assert_eq!(result.ty, fold_regions(tcx, result.ty, |_, _| tcx.lifetimes.re_erased));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use std::ops::ControlFlow;
|
|||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_NoContext;
|
||||
use rustc_type_ir::data_structures::{HashMap, HashSet};
|
||||
use rustc_type_ir::fast_reject::DeepRejectCtxt;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::relate::solver_relating::RelateExt;
|
||||
|
|
@ -1128,6 +1127,7 @@ where
|
|||
self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(super) fn register_hidden_type_in_storage(
|
||||
&mut self,
|
||||
opaque_type_key: ty::OpaqueTypeKey<I>,
|
||||
|
|
@ -1154,29 +1154,6 @@ where
|
|||
self.add_goals(GoalSource::AliasWellFormed, goals);
|
||||
}
|
||||
|
||||
// Do something for each opaque/hidden pair defined with `def_id` in the
|
||||
// current inference context.
|
||||
pub(super) fn probe_existing_opaque_ty(
|
||||
&mut self,
|
||||
key: ty::OpaqueTypeKey<I>,
|
||||
) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
|
||||
// We shouldn't have any duplicate entries when using
|
||||
// this function during `TypingMode::Analysis`.
|
||||
let duplicate_entries = self.delegate.clone_duplicate_opaque_types();
|
||||
assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}");
|
||||
let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
|
||||
|(candidate_key, _)| {
|
||||
candidate_key.def_id == key.def_id
|
||||
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
|
||||
.args_may_unify(candidate_key.args, key.args)
|
||||
},
|
||||
);
|
||||
let first = matching.next();
|
||||
let second = matching.next();
|
||||
assert_eq!(second, None);
|
||||
first
|
||||
}
|
||||
|
||||
// Try to evaluate a const, or return `None` if the const is too generic.
|
||||
// This doesn't mean the const isn't evaluatable, though, and should be treated
|
||||
// as an ambiguity rather than no-solution.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
//! Computes a normalizes-to (projection) goal for opaque types. This goal
|
||||
//! behaves differently depending on the current `TypingMode`.
|
||||
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::solve::GoalSource;
|
||||
use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions};
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect};
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
|
||||
impl<D, I> EvalCtxt<'_, D>
|
||||
where
|
||||
|
|
@ -39,100 +38,68 @@ where
|
|||
self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous));
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
TypingMode::Analysis { defining_opaque_types_and_generators } => {
|
||||
let Some(def_id) = opaque_ty
|
||||
.def_id
|
||||
.as_local()
|
||||
.filter(|&def_id| defining_opaque_types_and_generators.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);
|
||||
};
|
||||
|
||||
// FIXME: This may have issues when the args contain aliases...
|
||||
match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) {
|
||||
Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
|
||||
return self.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
Ok(()) => {}
|
||||
}
|
||||
// Prefer opaques registered already.
|
||||
let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
|
||||
// FIXME: This also unifies the previous hidden type with the expected.
|
||||
//
|
||||
// If that fails, we insert `expected` as a new hidden type instead of
|
||||
// eagerly emitting an error.
|
||||
let existing = self.probe_existing_opaque_ty(opaque_type_key);
|
||||
if let Some((candidate_key, candidate_ty)) = existing {
|
||||
return self
|
||||
.probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup {
|
||||
result: *result,
|
||||
})
|
||||
.enter(|ecx| {
|
||||
for (a, b) in std::iter::zip(
|
||||
candidate_key.args.iter(),
|
||||
opaque_type_key.args.iter(),
|
||||
) {
|
||||
ecx.eq(goal.param_env, a, b)?;
|
||||
}
|
||||
ecx.eq(goal.param_env, candidate_ty, expected)?;
|
||||
ecx.add_item_bounds_for_hidden_type(
|
||||
def_id.into(),
|
||||
candidate_key.args,
|
||||
goal.param_env,
|
||||
candidate_ty,
|
||||
);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise, define a new opaque type
|
||||
let prev = self.register_hidden_type_in_storage(opaque_type_key, expected);
|
||||
assert_eq!(prev, None);
|
||||
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::Analysis {
|
||||
defining_opaque_types_and_generators: defining_opaque_types,
|
||||
}
|
||||
// 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 } => {
|
||||
| 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 {
|
||||
// If we're not in the defining scope, treat the alias as rigid.
|
||||
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)?;
|
||||
// We structurally normalize the args so that we're able to detect defining uses
|
||||
// later on.
|
||||
//
|
||||
// This reduces the amount of duplicate definitions in the `opaque_type_storage` and
|
||||
// strengthens inference. This causes us to subtly depend on the normalization behavior
|
||||
// when inferring the hidden type of opaques.
|
||||
//
|
||||
// E.g. it's observable that we don't normalize nested aliases with bound vars in
|
||||
// `structurally_normalize` and because we use structural lookup, we also don't
|
||||
// reuse an entry for `Tait<for<'a> fn(&'a ())>` for `Tait<for<'b> fn(&'b ())>`.
|
||||
let normalized_args =
|
||||
cx.mk_args_from_iter(opaque_ty.args.iter().map(|arg| match arg.kind() {
|
||||
ty::GenericArgKind::Lifetime(lt) => Ok(lt.into()),
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
self.structurally_normalize_ty(goal.param_env, ty).map(Into::into)
|
||||
}
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
self.structurally_normalize_const(goal.param_env, ct).map(Into::into)
|
||||
}
|
||||
}))?;
|
||||
|
||||
let opaque_type_key = ty::OpaqueTypeKey { def_id, args: normalized_args };
|
||||
if let Some(prev) = self.register_hidden_type_in_storage(opaque_type_key, expected)
|
||||
{
|
||||
self.eq(goal.param_env, expected, prev)?;
|
||||
} else {
|
||||
// During HIR typeck, opaque types start out as unconstrained
|
||||
// inference variables. In borrowck we instead use the type
|
||||
// computed in HIR typeck as the initial value.
|
||||
match self.typing_mode() {
|
||||
TypingMode::Analysis { .. } => {}
|
||||
TypingMode::Borrowck { .. } => {
|
||||
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,
|
||||
});
|
||||
self.eq(goal.param_env, expected, actual)?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
self.add_item_bounds_for_hidden_type(
|
||||
def_id.into(),
|
||||
opaque_ty.args,
|
||||
normalized_args,
|
||||
goal.param_env,
|
||||
expected,
|
||||
);
|
||||
|
|
@ -168,44 +135,3 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether each generic argument is simply a unique generic placeholder.
|
||||
///
|
||||
/// FIXME: Interner argument is needed to constrain the `I` parameter.
|
||||
fn uses_unique_placeholders_ignoring_regions<I: Interner>(
|
||||
_cx: I,
|
||||
args: I::GenericArgs,
|
||||
) -> Result<(), NotUniqueParam<I>> {
|
||||
let mut seen = GrowableBitSet::default();
|
||||
for arg in args.iter() {
|
||||
match arg.kind() {
|
||||
// Ignore regions, since we can't resolve those in a canonicalized
|
||||
// query in the trait solver.
|
||||
ty::GenericArgKind::Lifetime(_) => {}
|
||||
ty::GenericArgKind::Type(t) => match t.kind() {
|
||||
ty::Placeholder(p) => {
|
||||
if !seen.insert(p.var()) {
|
||||
return Err(NotUniqueParam::DuplicateParam(t.into()));
|
||||
}
|
||||
}
|
||||
_ => return Err(NotUniqueParam::NotParam(t.into())),
|
||||
},
|
||||
ty::GenericArgKind::Const(c) => match c.kind() {
|
||||
ty::ConstKind::Placeholder(p) => {
|
||||
if !seen.insert(p.var()) {
|
||||
return Err(NotUniqueParam::DuplicateParam(c.into()));
|
||||
}
|
||||
}
|
||||
_ => return Err(NotUniqueParam::NotParam(c.into())),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// FIXME: This should check for dupes and non-params first, then infer vars.
|
||||
enum NotUniqueParam<I: Interner> {
|
||||
DuplicateParam(I::GenericArg),
|
||||
NotParam(I::GenericArg),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ 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,
|
||||
self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, Ty, TyCtxt,
|
||||
TypeVisitableExt, TypingMode, fold_regions,
|
||||
};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
|
||||
|
|
@ -14,22 +14,22 @@ use crate::regions::OutlivesEnvironmentBuildExt;
|
|||
use crate::traits::ObligationCtxt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InvalidOpaqueTypeArgs<'tcx> {
|
||||
AlreadyReported(ErrorGuaranteed),
|
||||
pub enum NonDefiningUseReason<'tcx> {
|
||||
Tainted(ErrorGuaranteed),
|
||||
NotAParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_index: usize, span: Span },
|
||||
DuplicateParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_indices: Vec<usize>, span: Span },
|
||||
}
|
||||
impl From<ErrorGuaranteed> for InvalidOpaqueTypeArgs<'_> {
|
||||
impl From<ErrorGuaranteed> for NonDefiningUseReason<'_> {
|
||||
fn from(guar: ErrorGuaranteed) -> Self {
|
||||
InvalidOpaqueTypeArgs::AlreadyReported(guar)
|
||||
NonDefiningUseReason::Tainted(guar)
|
||||
}
|
||||
}
|
||||
impl<'tcx> InvalidOpaqueTypeArgs<'tcx> {
|
||||
impl<'tcx> NonDefiningUseReason<'tcx> {
|
||||
pub fn report(self, infcx: &InferCtxt<'tcx>) -> ErrorGuaranteed {
|
||||
let tcx = infcx.tcx;
|
||||
match self {
|
||||
InvalidOpaqueTypeArgs::AlreadyReported(guar) => guar,
|
||||
InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index, span } => {
|
||||
NonDefiningUseReason::Tainted(guar) => guar,
|
||||
NonDefiningUseReason::NotAParam { opaque_type_key, param_index, span } => {
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let opaque_param = opaque_generics.param_at(param_index, tcx);
|
||||
let kind = opaque_param.kind.descr();
|
||||
|
|
@ -40,7 +40,7 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> {
|
|||
param_span: tcx.def_span(opaque_param.def_id),
|
||||
})
|
||||
}
|
||||
InvalidOpaqueTypeArgs::DuplicateParam { opaque_type_key, param_indices, span } => {
|
||||
NonDefiningUseReason::DuplicateParam { opaque_type_key, param_indices, span } => {
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let descr = opaque_generics.param_at(param_indices[0], tcx).kind.descr();
|
||||
let spans: Vec<_> = param_indices
|
||||
|
|
@ -58,15 +58,17 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> {
|
|||
}
|
||||
|
||||
/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter].
|
||||
/// With the new solver, uses which fail this check are simply treated as non-defining
|
||||
/// and we only emit an error if no defining use exists.
|
||||
///
|
||||
/// [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>(
|
||||
pub fn opaque_type_has_defining_use_args<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
span: Span,
|
||||
defining_scope_kind: DefiningScopeKind,
|
||||
) -> Result<(), InvalidOpaqueTypeArgs<'tcx>> {
|
||||
) -> Result<(), NonDefiningUseReason<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
|
||||
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
||||
|
|
@ -105,13 +107,13 @@ pub fn check_opaque_type_parameter_valid<'tcx>(
|
|||
} else {
|
||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||
opaque_env.param_is_error(i)?;
|
||||
return Err(InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index: i, span });
|
||||
return Err(NonDefiningUseReason::NotAParam { opaque_type_key, param_index: i, span });
|
||||
}
|
||||
}
|
||||
|
||||
for (_, param_indices) in seen_params {
|
||||
if param_indices.len() > 1 {
|
||||
return Err(InvalidOpaqueTypeArgs::DuplicateParam {
|
||||
return Err(NonDefiningUseReason::DuplicateParam {
|
||||
opaque_type_key,
|
||||
param_indices,
|
||||
span,
|
||||
|
|
@ -206,3 +208,27 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
|
|||
canonical_args
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_item_does_not_constrain_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: LocalDefId,
|
||||
def_id: LocalDefId,
|
||||
non_defining_use: Option<(OpaqueTypeKey<'tcx>, Span)>,
|
||||
) -> ErrorGuaranteed {
|
||||
let span = tcx.def_ident_span(item_def_id).unwrap_or_else(|| tcx.def_span(item_def_id));
|
||||
let opaque_type_span = tcx.def_span(def_id);
|
||||
let opaque_type_name = tcx.def_path_str(def_id);
|
||||
|
||||
let mut err =
|
||||
tcx.dcx().struct_span_err(span, format!("item does not constrain `{opaque_type_name}`"));
|
||||
err.note("consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`");
|
||||
err.span_note(opaque_type_span, "this opaque type is supposed to be constrained");
|
||||
if let Some((key, span)) = non_defining_use {
|
||||
let opaque_ty = Ty::new_opaque(tcx, key.def_id.into(), key.args);
|
||||
err.span_note(
|
||||
span,
|
||||
format!("this use of `{opaque_ty}` does not have unique universal generic arguments"),
|
||||
);
|
||||
}
|
||||
err.emit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,14 @@
|
|||
error[E0283]: type annotations needed
|
||||
--> $DIR/ambig-hr-projection-issue-93340.rs:17:5
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/ambig-hr-projection-issue-93340.rs:16:5
|
||||
|
|
||||
LL | cmp_eq
|
||||
| ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq`
|
||||
|
|
||||
= note: cannot satisfy `_: Scalar`
|
||||
note: required by a bound in `cmp_eq`
|
||||
--> $DIR/ambig-hr-projection-issue-93340.rs:10:22
|
||||
|
|
||||
LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
|
||||
| ^^^^^^ required by this bound in `cmp_eq`
|
||||
help: consider specifying the generic arguments
|
||||
|
|
||||
LL | cmp_eq::<A, B, O>
|
||||
| +++++++++++
|
||||
|
||||
error[E0277]: expected a `Fn(<A as Scalar>::RefType<'_>, <B as Scalar>::RefType<'_>)` closure, found `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::<O, _, O>}`
|
||||
--> $DIR/ambig-hr-projection-issue-93340.rs:14:1
|
||||
|
|
||||
LL | / fn build_expression<A: Scalar, B: Scalar, O: Scalar>(
|
||||
LL | | ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
|
||||
| |_________________________________________________^ expected an `Fn(<A as Scalar>::RefType<'_>, <B as Scalar>::RefType<'_>)` closure, found `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::<O, _, O>}`
|
||||
|
|
||||
= help: the trait `for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>)` is not implemented for fn item `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::<O, _, O>}`
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0283.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0283]: type annotations needed
|
||||
--> $DIR/ambig-hr-projection-issue-93340.rs:17:5
|
||||
--> $DIR/ambig-hr-projection-issue-93340.rs:16:5
|
||||
|
|
||||
LL | cmp_eq
|
||||
| ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq`
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefT
|
|||
|
||||
fn build_expression<A: Scalar, B: Scalar, O: Scalar>(
|
||||
) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
|
||||
//[next]~^^ ERROR expected a `Fn(<A as Scalar>::RefType<'_>, <B as Scalar>::RefType<'_>)` closure
|
||||
cmp_eq
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,9 @@
|
|||
error[E0283]: type annotations needed
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/auto-trait-selection-freeze.rs:19:16
|
||||
|
|
||||
LL | if false { is_trait(foo()) } else { Default::default() }
|
||||
| ^^^^^^^^ ----- type must be known at this point
|
||||
| |
|
||||
| cannot infer type of the type parameter `T` declared on the function `is_trait`
|
||||
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_trait`
|
||||
|
|
||||
= note: cannot satisfy `_: Trait<_>`
|
||||
note: required by a bound in `is_trait`
|
||||
--> $DIR/auto-trait-selection-freeze.rs:11:16
|
||||
|
|
||||
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
|
||||
| ^^^^^^^^ required by this bound in `is_trait`
|
||||
help: consider specifying the generic arguments
|
||||
|
|
||||
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
|
||||
|
|
@ -19,4 +11,4 @@ LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
|
|||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -1,17 +1,9 @@
|
|||
error[E0283]: type annotations needed
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/auto-trait-selection.rs:15:16
|
||||
|
|
||||
LL | if false { is_trait(foo()) } else { Default::default() }
|
||||
| ^^^^^^^^ ----- type must be known at this point
|
||||
| |
|
||||
| cannot infer type of the type parameter `T` declared on the function `is_trait`
|
||||
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_trait`
|
||||
|
|
||||
= note: cannot satisfy `_: Trait<_>`
|
||||
note: required by a bound in `is_trait`
|
||||
--> $DIR/auto-trait-selection.rs:7:16
|
||||
|
|
||||
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
|
||||
| ^^^^^^^^ required by this bound in `is_trait`
|
||||
help: consider specifying the generic arguments
|
||||
|
|
||||
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
|
||||
|
|
@ -19,4 +11,4 @@ LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
|
|||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ LL | fn build2<T>(x: T) -> impl Sized {
|
|||
| ^^^^^^^^^^
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:39:23
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:37:23
|
||||
|
|
||||
LL | fn build3<T>(x: T) -> impl Sized {
|
||||
| ^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -1,80 +1,21 @@
|
|||
error[E0284]: type annotations needed: cannot normalize `build<_>::{opaque#0}`
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:20:5
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:19:17
|
||||
|
|
||||
LL | build(x)
|
||||
| ^^^^^^^^ cannot normalize `build<_>::{opaque#0}`
|
||||
LL | let (x,) = (build(x),);
|
||||
| ^^^^^^^^ cannot infer type
|
||||
|
||||
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:30:6
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:29:17
|
||||
|
|
||||
LL | (build2(x),)
|
||||
| ^^^^^^^^^ types differ
|
||||
LL | let (x,) = (build2(x),);
|
||||
| ^^^^^^^^^ cannot infer type
|
||||
|
||||
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:30:5
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:40:5
|
||||
|
|
||||
LL | (build2(x),)
|
||||
| ^^^^^^^^^^^^ types differ
|
||||
LL | build3(x)
|
||||
| ^^^^^^^^^ cannot infer type
|
||||
|
||||
error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:30:5
|
||||
|
|
||||
LL | (build2(x),)
|
||||
| ^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(impl Sized,)`
|
||||
= note: tuples must have a statically known size to be initialized
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:41:17
|
||||
|
|
||||
LL | let (x,) = (build3((x,)),);
|
||||
| ^^^^^^^^^^^^ types differ
|
||||
|
||||
error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:41:16
|
||||
|
|
||||
LL | let (x,) = (build3((x,)),);
|
||||
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(impl Sized,)`
|
||||
= note: tuples must have a statically known size to be initialized
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:41:16
|
||||
|
|
||||
LL | fn build3<T>(x: T) -> impl Sized {
|
||||
| ---------- the found opaque type
|
||||
LL |
|
||||
LL | let (x,) = (build3((x,)),);
|
||||
| ^^^^^^^^^^^^^^^ types differ
|
||||
|
|
||||
= note: expected type `_`
|
||||
found tuple `(impl Sized,)`
|
||||
|
||||
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:41:17
|
||||
|
|
||||
LL | let (x,) = (build3((x,)),);
|
||||
| ^^^^^^^^^^^^ types differ
|
||||
|
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:41:16
|
||||
|
|
||||
LL | let (x,) = (build3((x,)),);
|
||||
| ^^^^^^^^^^^^^^^ types differ
|
||||
|
||||
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
|
||||
--> $DIR/recursive-in-exhaustiveness.rs:41:17
|
||||
|
|
||||
LL | let (x,) = (build3((x,)),);
|
||||
| ^^^^^^^^^^^^ types differ
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0277, E0284, E0308.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
fn build<T>(x: T) -> impl Sized {
|
||||
//[current]~^ ERROR cannot resolve opaque type
|
||||
let (x,) = (build(x),);
|
||||
//[next]~^ ERROR type annotations needed
|
||||
build(x)
|
||||
//[next]~^ ERROR type annotations needed: cannot normalize `build<_>::{opaque#0}`
|
||||
}
|
||||
|
||||
// Opaque<T> = (Opaque<T>,)
|
||||
|
|
@ -27,10 +27,8 @@ fn build<T>(x: T) -> impl Sized {
|
|||
fn build2<T>(x: T) -> impl Sized {
|
||||
//[current]~^ ERROR cannot resolve opaque type
|
||||
let (x,) = (build2(x),);
|
||||
//[next]~^ ERROR type annotations needed
|
||||
(build2(x),)
|
||||
//[next]~^ ERROR type mismatch resolving
|
||||
//[next]~| ERROR type mismatch resolving
|
||||
//[next]~| ERROR the size for values of type
|
||||
}
|
||||
|
||||
// Opaque<T> = Opaque<(T,)>
|
||||
|
|
@ -39,13 +37,8 @@ fn build2<T>(x: T) -> impl Sized {
|
|||
fn build3<T>(x: T) -> impl Sized {
|
||||
//[current]~^ ERROR cannot resolve opaque type
|
||||
let (x,) = (build3((x,)),);
|
||||
//[next]~^ ERROR type mismatch resolving
|
||||
//[next]~| ERROR type mismatch resolving
|
||||
//[next]~| ERROR type mismatch resolving
|
||||
//[next]~| ERROR type mismatch resolving
|
||||
//[next]~| ERROR the size for values of type
|
||||
//[next]~| ERROR mismatched types
|
||||
build3(x)
|
||||
//[next]~^ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
error[E0282]: type annotations needed
|
||||
--> $DIR/two_tait_defining_each_other2.rs:12:11
|
||||
--> $DIR/two_tait_defining_each_other2.rs:12:8
|
||||
|
|
||||
LL | fn muh(x: A) -> B {
|
||||
| ^ cannot infer type
|
||||
| ^ cannot infer type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/two_tait_defining_each_other2.rs:14:5
|
||||
|
|
||||
LL | x // B's hidden type is A (opaquely)
|
||||
| ^ cannot infer type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ trait Foo {}
|
|||
fn muh(x: A) -> B {
|
||||
//[next]~^ ERROR: type annotations needed
|
||||
x // B's hidden type is A (opaquely)
|
||||
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type
|
||||
//[next]~^ ERROR: type annotations needed
|
||||
//[current]~^^ ERROR opaque type's hidden type cannot be another opaque type
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
error: concrete type differs from previous defining opaque type use
|
||||
--> $DIR/different-bound-vars.rs:13:37
|
||||
|
|
||||
LL | let _: for<'b> fn(&'b ()) = foo::<U, T>(false);
|
||||
| ^^^^^^^^^^^^^^^^^^ expected `for<'a> fn(&'a ())`, got `for<'b> fn(&'b ())`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/different-bound-vars.rs:12:37
|
||||
|
|
||||
LL | let _: for<'a> fn(&'a ()) = foo::<T, U>(false);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
20
tests/ui/traits/next-solver/opaques/different-bound-vars.rs
Normal file
20
tests/ui/traits/next-solver/opaques/different-bound-vars.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// Check whether we support defining uses with different bound vars.
|
||||
// This needs to handle both mismatches for the same opaque type storage
|
||||
// entry, but also between different entries.
|
||||
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@[next] check-pass
|
||||
|
||||
fn foo<T, U>(b: bool) -> impl Sized {
|
||||
if b {
|
||||
let _: for<'a> fn(&'a ()) = foo::<T, U>(false);
|
||||
let _: for<'b> fn(&'b ()) = foo::<U, T>(false);
|
||||
//[current]~^ ERROR concrete type differs from previous defining opaque type use
|
||||
}
|
||||
|
||||
(|&()| ()) as for<'c> fn(&'c ())
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,16 +1,9 @@
|
|||
error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
|
||||
--> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:12
|
||||
|
|
||||
LL | needs_send::<Foo>();
|
||||
| ^^^
|
||||
|
|
||||
= note: cannot satisfy `Foo: Send`
|
||||
note: required by a bound in `needs_send`
|
||||
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
||||
|
|
||||
LL | fn needs_send<T: Send>() {}
|
||||
| ^^^^ required by this bound in `needs_send`
|
||||
LL | fn test(_: Foo) {
|
||||
| ^^^ cannot infer type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -1,16 +1,9 @@
|
|||
error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
|
||||
--> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:12
|
||||
|
|
||||
LL | needs_send::<Foo>();
|
||||
| ^^^
|
||||
|
|
||||
= note: cannot satisfy `Foo: Send`
|
||||
note: required by a bound in `needs_send`
|
||||
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
||||
|
|
||||
LL | fn needs_send<T: Send>() {}
|
||||
| ^^^^ required by this bound in `needs_send`
|
||||
LL | fn test(_: Foo) {
|
||||
| ^^^ cannot infer type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ fn needs_send<T: Send>() {}
|
|||
|
||||
#[define_opaque(Foo)]
|
||||
fn test(_: Foo) {
|
||||
needs_send::<Foo>();
|
||||
//~^ ERROR type annotations needed
|
||||
needs_send::<Foo>();
|
||||
}
|
||||
|
||||
#[define_opaque(Foo)]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
//@ ignore-compare-mode-next-solver
|
||||
//@ compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
// Make sure that we support non-defining uses in HIR typeck.
|
||||
// Regression test for trait-system-refactor-initiative#135.
|
||||
|
||||
fn non_defining_recurse<T>(b: bool) -> impl Sized {
|
||||
if b {
|
||||
// This results in an opaque type use `opaque<()> = ?unconstrained`
|
||||
// during HIR typeck.
|
||||
non_defining_recurse::<()>(false);
|
||||
}
|
||||
}
|
||||
|
||||
trait Eq<T, U> {}
|
||||
impl<T> Eq<T, T> for () {}
|
||||
fn is_eq<T: Eq<U, V>, U, V>() {}
|
||||
type Tait<T> = impl Sized;
|
||||
#[define_opaque(Tait)]
|
||||
fn non_defining_explicit<T>() {
|
||||
is_eq::<(), Tait<_>, u32>(); // constrains opaque type args via hidden type
|
||||
is_eq::<(), Tait<u64>, _>(); // constraints hidden type via args
|
||||
is_eq::<(), Tait<T>, T>(); // actually defines
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
//@ check-pass
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
// The recursive call to `foo` results in the opaque type use `opaque<U, T> = ?unconstrained`.
|
||||
// This needs to be supported and treated as a revealing use.
|
||||
|
||||
fn foo<T, U>(b: bool) -> impl Sized {
|
||||
if b {
|
||||
foo::<U, T>(b);
|
||||
}
|
||||
1u16
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,24 +1,9 @@
|
|||
error[E0283]: type annotations needed: cannot satisfy `Foo: Trait<Bar>`
|
||||
--> $DIR/constrain_in_projection2.rs:28:14
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/constrain_in_projection2.rs:28:13
|
||||
|
|
||||
LL | let x = <Foo as Trait<Bar>>::Assoc::default();
|
||||
| ^^^
|
||||
|
|
||||
note: multiple `impl`s satisfying `Foo: Trait<Bar>` found
|
||||
--> $DIR/constrain_in_projection2.rs:18:1
|
||||
|
|
||||
LL | impl Trait<()> for Foo {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | impl Trait<u32> for Foo {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
|
||||
help: use the fully qualified path to an implementation
|
||||
|
|
||||
LL - let x = <Foo as Trait<Bar>>::Assoc::default();
|
||||
LL + let x = <<Type as Trait>::Assoc as Trait<Bar>>::Assoc::default();
|
||||
|
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl Trait<u32> for Foo {
|
|||
#[define_opaque(Bar)]
|
||||
fn bop() {
|
||||
let x = <Foo as Trait<Bar>>::Assoc::default();
|
||||
//[next]~^ ERROR: cannot satisfy `Foo: Trait<Bar>`
|
||||
//[next]~^ ERROR: type annotations needed
|
||||
//[current]~^^ ERROR: `Foo: Trait<Bar>` is not satisfied
|
||||
//[current]~| ERROR: `Foo: Trait<Bar>` is not satisfied
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0792]: expected generic type parameter, found `u32`
|
||||
--> $DIR/generic_nondefining_use.rs:16:21
|
||||
--> $DIR/generic_nondefining_use.rs:20:21
|
||||
|
|
||||
LL | type OneTy<T> = impl Debug;
|
||||
| - this generic parameter must be used with a generic type parameter
|
||||
|
|
@ -8,7 +8,7 @@ LL | fn concrete_ty() -> OneTy<u32> {
|
|||
| ^^^^^^^^^^
|
||||
|
||||
error[E0792]: expected generic lifetime parameter, found `'static`
|
||||
--> $DIR/generic_nondefining_use.rs:23:5
|
||||
--> $DIR/generic_nondefining_use.rs:29:5
|
||||
|
|
||||
LL | type OneLifetime<'a> = impl Debug;
|
||||
| -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
|
||||
|
|
@ -17,7 +17,7 @@ LL | 6u32
|
|||
| ^^^^
|
||||
|
||||
error[E0792]: expected generic constant parameter, found `123`
|
||||
--> $DIR/generic_nondefining_use.rs:28:24
|
||||
--> $DIR/generic_nondefining_use.rs:35:24
|
||||
|
|
||||
LL | type OneConst<const X: usize> = impl Debug;
|
||||
| -------------- this generic parameter must be used with a generic constant parameter
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
error: item does not constrain `OneTy::{opaque#0}`
|
||||
--> $DIR/generic_nondefining_use.rs:20:4
|
||||
|
|
||||
LL | fn concrete_ty() -> OneTy<u32> {
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
|
||||
note: this opaque type is supposed to be constrained
|
||||
--> $DIR/generic_nondefining_use.rs:11:17
|
||||
|
|
||||
LL | type OneTy<T> = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
note: this use of `OneTy<u32>` does not have unique universal generic arguments
|
||||
--> $DIR/generic_nondefining_use.rs:23:5
|
||||
|
|
||||
LL | 5u32
|
||||
| ^^^^
|
||||
|
||||
error: non-defining use of `OneLifetime<'_>` in the defining scope
|
||||
--> $DIR/generic_nondefining_use.rs:27:1
|
||||
|
|
||||
LL | fn concrete_lifetime() -> OneLifetime<'static> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: item does not constrain `OneConst::{opaque#0}`
|
||||
--> $DIR/generic_nondefining_use.rs:35:4
|
||||
|
|
||||
LL | fn concrete_const() -> OneConst<{ 123 }> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
|
||||
note: this opaque type is supposed to be constrained
|
||||
--> $DIR/generic_nondefining_use.rs:15:33
|
||||
|
|
||||
LL | type OneConst<const X: usize> = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
note: this use of `OneConst<123>` does not have unique universal generic arguments
|
||||
--> $DIR/generic_nondefining_use.rs:38:5
|
||||
|
|
||||
LL | 7u32
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -14,18 +18,22 @@ type OneConst<const X: usize> = impl Debug;
|
|||
|
||||
#[define_opaque(OneTy)]
|
||||
fn concrete_ty() -> OneTy<u32> {
|
||||
//~^ ERROR: expected generic type parameter, found `u32`
|
||||
//[current]~^ ERROR: expected generic type parameter, found `u32`
|
||||
//[next]~^^ ERROR: item does not constrain `OneTy::{opaque#0}`
|
||||
5u32
|
||||
}
|
||||
|
||||
#[define_opaque(OneLifetime)]
|
||||
fn concrete_lifetime() -> OneLifetime<'static> {
|
||||
//[next]~^ ERROR: non-defining use of `OneLifetime<'_>` in the defining scope
|
||||
6u32
|
||||
//~^ ERROR: expected generic lifetime parameter, found `'static`
|
||||
//[current]~^ ERROR: expected generic lifetime parameter, found `'static`
|
||||
|
||||
}
|
||||
|
||||
#[define_opaque(OneConst)]
|
||||
fn concrete_const() -> OneConst<{ 123 }> {
|
||||
//~^ ERROR: expected generic constant parameter, found `123`
|
||||
//[current]~^ ERROR: expected generic constant parameter, found `123`
|
||||
//[next]~^^ ERROR: item does not constrain `OneConst::{opaque#0}`
|
||||
7u32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
|
||||
// Regression test for trait-system-refactor-initiative#49.
|
||||
|
||||
trait Mirror<'a> {
|
||||
type Assoc;
|
||||
}
|
||||
impl<'a, T> Mirror<'a> for T {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
type HrAmbigAlias<T> = impl Sized;
|
||||
fn ret_tait<T>() -> for<'a> fn(HrAmbigAlias<<T as Mirror<'a>>::Assoc>) {
|
||||
|_| ()
|
||||
}
|
||||
|
||||
#[define_opaque(HrAmbigAlias)]
|
||||
fn define_hr_ambig_alias<T>() {
|
||||
let _: fn(T) = ret_tait::<T>();
|
||||
}
|
||||
|
||||
type InUserType<T> = impl Sized;
|
||||
#[define_opaque(InUserType)]
|
||||
fn in_user_type<T>() {
|
||||
let x: InUserType<<T as Mirror<'static>>::Assoc> = ();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue