Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 9 additions & 12 deletions compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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));
}

Expand Down Expand Up @@ -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,
Expand All @@ -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
}
}
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
215 changes: 214 additions & 1 deletion compiler/rustc_hir_typeck/src/opaque_types.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand Down
Loading
Loading