diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 33c4879af9809..bee82e17835f8 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -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, InvalidOpaqueTypeArgs<'tcx>> { - check_opaque_type_parameter_valid( + ) -> Result, NonDefiningUseReason<'tcx>> { + opaque_type_has_defining_use_args( self, opaque_type_key, instantiated_ty.span, diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 2428c1aa29fc8..06f2ec512ab1f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -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 diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 50e20a19edaef..b6d898886ac4d 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -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 } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 26a98722b341e..6565ad7cf5367 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -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, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3a153ab089a46..44a5ceed46961 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -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; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 634647a595a1c..879b74727366d 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -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(); } diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index e0224f8c6e1b4..97feac3d0099a 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -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. /// diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 131c687bddc6a..253eacbf35393 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -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( &mut self, value: T, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a7298af502ef1..e567ba05f61cb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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 } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 0230f784e4694..4f87902e46e95 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -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, @@ -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, - ) -> Option<(ty::OpaqueTypeKey, 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. diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index df3ad1e468bb8..a5f857a1dd85b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -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 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 } => { + TypingMode::Analysis { + defining_opaque_types_and_generators: defining_opaque_types, + } + | TypingMode::Borrowck { defining_opaque_types } => { let Some(def_id) = opaque_ty .def_id .as_local() - .filter(|&def_id| defining_opaque_types_and_generators.contains(&def_id)) + .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); }; - // 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. + // We structurally normalize the args so that we're able to detect defining uses + // later on. // - // 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) - }); - } + // 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 fn(&'a ())>` for `Tait 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) + } + }))?; - // 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) - } - // 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: 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!(), + } + } - 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, + 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( - _cx: I, - args: I::GenericArgs, -) -> Result<(), NotUniqueParam> { - 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 { - DuplicateParam(I::GenericArg), - NotParam(I::GenericArg), -} diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 70a08f34f336b..bc7bdd372baa6 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -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, span: Span }, } -impl From for InvalidOpaqueTypeArgs<'_> { +impl From 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` 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() +} diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr index d624fb1e42b6f..d6294efbd2803 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr @@ -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:: | +++++++++++ -error[E0277]: expected a `Fn(::RefType<'_>, ::RefType<'_>)` closure, found `for<'a, 'b> fn(::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::}` - --> $DIR/ambig-hr-projection-issue-93340.rs:14:1 - | -LL | / fn build_expression( -LL | | ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { - | |_________________________________________________^ expected an `Fn(::RefType<'_>, ::RefType<'_>)` closure, found `for<'a, 'b> fn(::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::}` - | - = help: the trait `for<'a, 'b> Fn(::RefType<'a>, ::RefType<'b>)` is not implemented for fn item `for<'a, 'b> fn(::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::}` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -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`. diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr index 4a293d44e0e3d..d913b2e91ca0e 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr @@ -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` diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs index 6ba3c4c65d070..acfebad38db0c 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs @@ -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( ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { - //[next]~^^ ERROR expected a `Fn(::RefType<'_>, ::RefType<'_>)` closure cmp_eq //~^ ERROR type annotations needed } diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr index 5caf0eb2fd4e3..7170efc863870 100644 --- a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr @@ -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, U: Default>(_: T) -> U { - | ^^^^^^^^ required by this bound in `is_trait` help: consider specifying the generic arguments | LL | if false { is_trait::(foo()) } else { Default::default() } @@ -19,4 +11,4 @@ LL | if false { is_trait::(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`. diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr index d34fdcc44967f..0f33aca301914 100644 --- a/tests/ui/impl-trait/auto-trait-selection.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr @@ -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, U: Default>(_: T) -> U { - | ^^^^^^^^ required by this bound in `is_trait` help: consider specifying the generic arguments | LL | if false { is_trait::(foo()) } else { Default::default() } @@ -19,4 +11,4 @@ LL | if false { is_trait::(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`. diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr index 080c328464153..11a88b0918ce5 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr @@ -11,7 +11,7 @@ LL | fn build2(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(x: T) -> impl Sized { | ^^^^^^^^^^ diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr index db57be73acceb..45df8cc9c0ca9 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr @@ -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[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(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 +error: aborting due to 3 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`. diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs index dabef22af8681..7aee8a630a5c8 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs @@ -17,8 +17,8 @@ fn build(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 = (Opaque,) @@ -27,10 +27,8 @@ fn build(x: T) -> impl Sized { fn build2(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 = Opaque<(T,)> @@ -39,13 +37,8 @@ fn build2(x: T) -> impl Sized { fn build3(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() {} diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr index fac4776905d06..785e5fdeb6433 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr @@ -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`. diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs index ec2963249f9da..99262f4bc4b38 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs @@ -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; diff --git a/tests/ui/traits/next-solver/opaques/different-bound-vars.current.stderr b/tests/ui/traits/next-solver/opaques/different-bound-vars.current.stderr new file mode 100644 index 0000000000000..32e92e46a888b --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/different-bound-vars.current.stderr @@ -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::(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::(false); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/next-solver/opaques/different-bound-vars.rs b/tests/ui/traits/next-solver/opaques/different-bound-vars.rs new file mode 100644 index 0000000000000..5801a5edeb4ab --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/different-bound-vars.rs @@ -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(b: bool) -> impl Sized { + if b { + let _: for<'a> fn(&'a ()) = foo::(false); + let _: for<'b> fn(&'b ()) = foo::(false); + //[current]~^ ERROR concrete type differs from previous defining opaque type use + } + + (|&()| ()) as for<'c> fn(&'c ()) +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr index 6d2bbd8b08b4c..a188629a4758b 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr @@ -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::(); - | ^^^ - | - = 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() {} - | ^^^^ 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`. diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr index 6d2bbd8b08b4c..a188629a4758b 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -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::(); - | ^^^ - | - = 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() {} - | ^^^^ 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`. diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs index fddf892e1ef1d..8ff99d32f064f 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs @@ -13,8 +13,8 @@ fn needs_send() {} #[define_opaque(Foo)] fn test(_: Foo) { - needs_send::(); //~^ ERROR type annotations needed + needs_send::(); } #[define_opaque(Foo)] diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-hir-typeck.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-hir-typeck.rs new file mode 100644 index 0000000000000..a55be5fde9ec7 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-hir-typeck.rs @@ -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(b: bool) -> impl Sized { + if b { + // This results in an opaque type use `opaque<()> = ?unconstrained` + // during HIR typeck. + non_defining_recurse::<()>(false); + } +} + +trait Eq {} +impl Eq for () {} +fn is_eq, U, V>() {} +type Tait = impl Sized; +#[define_opaque(Tait)] +fn non_defining_explicit() { + is_eq::<(), Tait<_>, u32>(); // constrains opaque type args via hidden type + is_eq::<(), Tait, _>(); // constraints hidden type via args + is_eq::<(), Tait, T>(); // actually defines +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs b/tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs new file mode 100644 index 0000000000000..5e7e9738616cf --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs @@ -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 = ?unconstrained`. +// This needs to be supported and treated as a revealing use. + +fn foo(b: bool) -> impl Sized { + if b { + foo::(b); + } + 1u16 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr index 72a253c4be813..b50d1b60c43db 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr @@ -1,24 +1,9 @@ -error[E0283]: type annotations needed: cannot satisfy `Foo: Trait` - --> $DIR/constrain_in_projection2.rs:28:14 +error[E0282]: type annotations needed + --> $DIR/constrain_in_projection2.rs:28:13 | LL | let x = >::Assoc::default(); - | ^^^ - | -note: multiple `impl`s satisfying `Foo: Trait` found - --> $DIR/constrain_in_projection2.rs:18:1 - | -LL | impl Trait<()> for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^ -... -LL | impl Trait 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 = >::Assoc::default(); -LL + let x = <::Assoc as Trait>::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`. diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs b/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs index 61773cf59d475..c4aa6f32eab1e 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs @@ -26,7 +26,7 @@ impl Trait for Foo { #[define_opaque(Bar)] fn bop() { let x = >::Assoc::default(); - //[next]~^ ERROR: cannot satisfy `Foo: Trait` + //[next]~^ ERROR: type annotations needed //[current]~^^ ERROR: `Foo: Trait` is not satisfied //[current]~| ERROR: `Foo: Trait` is not satisfied } diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.current.stderr similarity index 88% rename from tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr rename to tests/ui/type-alias-impl-trait/generic_nondefining_use.current.stderr index 71e415271ee82..2a78860689b9b 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.current.stderr @@ -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 = impl Debug; | - this generic parameter must be used with a generic type parameter @@ -8,7 +8,7 @@ LL | fn concrete_ty() -> OneTy { | ^^^^^^^^^^ 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 = impl Debug; | -------------- this generic parameter must be used with a generic constant parameter diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.next.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.next.stderr new file mode 100644 index 0000000000000..2b53614ee3f00 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.next.stderr @@ -0,0 +1,44 @@ +error: item does not constrain `OneTy::{opaque#0}` + --> $DIR/generic_nondefining_use.rs:20:4 + | +LL | fn concrete_ty() -> OneTy { + | ^^^^^^^^^^^ + | + = 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 = impl Debug; + | ^^^^^^^^^^ +note: this use of `OneTy` 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 = 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 + diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs index cf38c93bd921e..7250a9ac0b3ad 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs @@ -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 = impl Debug; #[define_opaque(OneTy)] fn concrete_ty() -> OneTy { - //~^ 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 } diff --git a/tests/ui/type-alias-impl-trait/normalize-args-before-defining-use-check.rs b/tests/ui/type-alias-impl-trait/normalize-args-before-defining-use-check.rs new file mode 100644 index 0000000000000..2879b8fe94c8c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/normalize-args-before-defining-use-check.rs @@ -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 = impl Sized; +fn ret_tait() -> for<'a> fn(HrAmbigAlias<>::Assoc>) { + |_| () +} + +#[define_opaque(HrAmbigAlias)] +fn define_hr_ambig_alias() { + let _: fn(T) = ret_tait::(); +} + +type InUserType = impl Sized; +#[define_opaque(InUserType)] +fn in_user_type() { + let x: InUserType<>::Assoc> = (); +} + +fn main() {}