Skip to content

Commit 0dd5730

Browse files
committed
Auto merge of #114076 - matthiaskrgr:rollup-cpqq1n9, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #112995 (Check for `<&NotClone as Clone>::clone()` calls and suggest to add Clone trait appropriately) - #113578 (Don't say that a type is uncallable if its fn signature has errors in it) - #113661 (Double check that hidden types match the expected hidden type) - #114044 (factor out more stable impls) - #114062 (CI: split nested GHA groups instead of panicking) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 864bdf7 + c80a9fa commit 0dd5730

File tree

16 files changed

+852
-87
lines changed

16 files changed

+852
-87
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ fn check_opaque_type_well_formed<'tcx>(
339339
// version.
340340
let errors = ocx.select_all_or_error();
341341

342-
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
343-
// tests to pass
342+
// This is fishy, but we check it again in `check_opaque_meets_bounds`.
343+
// Remove once we can prepopulate with known hidden types.
344344
let _ = infcx.take_opaque_types();
345345

346346
if errors.is_empty() {

compiler/rustc_const_eval/src/util/compare_types.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,13 @@ pub fn is_subtype<'tcx>(
5656
// With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing`
5757
// we would get unification errors because we're unable to look into opaque types,
5858
// even if they're constrained in our current function.
59-
//
60-
// It seems very unlikely that this hides any bugs.
61-
let _ = infcx.take_opaque_types();
59+
for (key, ty) in infcx.take_opaque_types() {
60+
span_bug!(
61+
ty.hidden_type.span,
62+
"{}, {}",
63+
tcx.type_of(key.def_id).instantiate(tcx, key.args),
64+
ty.hidden_type.ty
65+
);
66+
}
6267
errors.is_empty()
6368
}

compiler/rustc_hir_analysis/src/check/check.rs

+175-4
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
1919
use rustc_middle::hir::nested_filter;
2020
use rustc_middle::middle::stability::EvalResult;
2121
use rustc_middle::traits::DefiningAnchor;
22+
use rustc_middle::ty::fold::BottomUpFolder;
2223
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
2324
use rustc_middle::ty::util::{Discr, IntTypeExt};
2425
use rustc_middle::ty::GenericArgKind;
2526
use rustc_middle::ty::{
26-
self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
27+
self, AdtDef, ParamEnv, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
28+
TypeVisitableExt,
2729
};
2830
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
2931
use rustc_span::symbol::sym;
@@ -34,6 +36,7 @@ use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplem
3436
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
3537
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
3638
use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
39+
use rustc_type_ir::fold::TypeFoldable;
3740

3841
use std::ops::ControlFlow;
3942

@@ -437,7 +440,7 @@ fn check_opaque_meets_bounds<'tcx>(
437440
// hidden type is well formed even without those bounds.
438441
let predicate =
439442
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));
440-
ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate));
443+
ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate));
441444

442445
// Check that all obligations are satisfied by the implementation's
443446
// version.
@@ -464,11 +467,179 @@ fn check_opaque_meets_bounds<'tcx>(
464467
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
465468
}
466469
}
467-
// Clean up after ourselves
468-
let _ = infcx.take_opaque_types();
470+
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
471+
for (key, mut ty) in infcx.take_opaque_types() {
472+
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
473+
sanity_check_found_hidden_type(tcx, key, ty.hidden_type, defining_use_anchor, origin)?;
474+
}
469475
Ok(())
470476
}
471477

478+
fn sanity_check_found_hidden_type<'tcx>(
479+
tcx: TyCtxt<'tcx>,
480+
key: ty::OpaqueTypeKey<'tcx>,
481+
mut ty: ty::OpaqueHiddenType<'tcx>,
482+
defining_use_anchor: LocalDefId,
483+
origin: &hir::OpaqueTyOrigin,
484+
) -> Result<(), ErrorGuaranteed> {
485+
if ty.ty.is_ty_var() {
486+
// Nothing was actually constrained.
487+
return Ok(());
488+
}
489+
if let ty::Alias(ty::Opaque, alias) = ty.ty.kind() {
490+
if alias.def_id == key.def_id.to_def_id() && alias.args == key.args {
491+
// Nothing was actually constrained, this is an opaque usage that was
492+
// only discovered to be opaque after inference vars resolved.
493+
return Ok(());
494+
}
495+
}
496+
// Closures frequently end up containing erased lifetimes in their final representation.
497+
// These correspond to lifetime variables that never got resolved, so we patch this up here.
498+
ty.ty = ty.ty.fold_with(&mut BottomUpFolder {
499+
tcx,
500+
ty_op: |t| t,
501+
ct_op: |c| c,
502+
lt_op: |l| match l.kind() {
503+
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
504+
_ => l,
505+
},
506+
});
507+
// Get the hidden type.
508+
let mut hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
509+
if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
510+
if hidden_ty != ty.ty {
511+
hidden_ty = find_and_apply_rpit_args(
512+
tcx,
513+
hidden_ty,
514+
defining_use_anchor.to_def_id(),
515+
key.def_id.to_def_id(),
516+
)?;
517+
}
518+
}
519+
520+
// If the hidden types differ, emit a type mismatch diagnostic.
521+
if hidden_ty == ty.ty {
522+
Ok(())
523+
} else {
524+
let span = tcx.def_span(key.def_id);
525+
let other = ty::OpaqueHiddenType { ty: hidden_ty, span };
526+
Err(ty.report_mismatch(&other, key.def_id, tcx).emit())
527+
}
528+
}
529+
530+
/// In case it is in a nested opaque type, find that opaque type's
531+
/// usage in the function signature and use the generic arguments from the usage site.
532+
/// We need to do because RPITs ignore the lifetimes of the function,
533+
/// as they have their own copies of all the lifetimes they capture.
534+
/// So the only way to get the lifetimes represented in terms of the function,
535+
/// is to look how they are used in the function signature (or do some other fancy
536+
/// recording of this mapping at ast -> hir lowering time).
537+
///
538+
/// As an example:
539+
/// ```text
540+
/// trait Id {
541+
/// type Assoc;
542+
/// }
543+
/// impl<'a> Id for &'a () {
544+
/// type Assoc = &'a ();
545+
/// }
546+
/// fn func<'a>(x: &'a ()) -> impl Id<Assoc = impl Sized + 'a> { x }
547+
/// // desugared to
548+
/// fn func<'a>(x: &'a () -> Outer<'a> where <Outer<'a> as Id>::Assoc = Inner<'a> {
549+
/// // Note that in contrast to other nested items, RPIT type aliases can
550+
/// // access their parents' generics.
551+
///
552+
/// // hidden type is `&'aDupOuter ()`
553+
/// // During wfcheck the hidden type of `Inner<'aDupOuter>` is `&'a ()`, but
554+
/// // `typeof(Inner<'aDupOuter>) = &'aDupOuter ()`.
555+
/// // So we walk the signature of `func` to find the use of `Inner<'a>`
556+
/// // and then use that to replace the lifetimes in the hidden type, obtaining
557+
/// // `&'a ()`.
558+
/// type Outer<'aDupOuter> = impl Id<Assoc = Inner<'aDupOuter>>;
559+
///
560+
/// // hidden type is `&'aDupInner ()`
561+
/// type Inner<'aDupInner> = impl Sized + 'aDupInner;
562+
///
563+
/// x
564+
/// }
565+
/// ```
566+
fn find_and_apply_rpit_args<'tcx>(
567+
tcx: TyCtxt<'tcx>,
568+
mut hidden_ty: Ty<'tcx>,
569+
function: DefId,
570+
opaque: DefId,
571+
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
572+
// Find use of the RPIT in the function signature and thus find the right args to
573+
// convert it into the parameter space of the function signature. This is needed,
574+
// because that's what `type_of` returns, against which we compare later.
575+
let ret = tcx.fn_sig(function).instantiate_identity().output();
576+
struct Visitor<'tcx> {
577+
tcx: TyCtxt<'tcx>,
578+
opaque: DefId,
579+
function: DefId,
580+
seen: FxHashSet<DefId>,
581+
}
582+
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
583+
type BreakTy = GenericArgsRef<'tcx>;
584+
585+
#[instrument(level = "trace", skip(self), ret)]
586+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
587+
trace!("{:#?}", t.kind());
588+
match t.kind() {
589+
ty::Alias(ty::Opaque, alias) => {
590+
trace!(?alias.def_id);
591+
if alias.def_id == self.opaque {
592+
return ControlFlow::Break(alias.args);
593+
} else if self.seen.insert(alias.def_id) {
594+
for clause in self
595+
.tcx
596+
.explicit_item_bounds(alias.def_id)
597+
.iter_instantiated_copied(self.tcx, alias.args)
598+
{
599+
trace!(?clause);
600+
clause.visit_with(self)?;
601+
}
602+
}
603+
}
604+
ty::Alias(ty::Projection, alias) => {
605+
if self.tcx.is_impl_trait_in_trait(alias.def_id)
606+
&& self.tcx.impl_trait_in_trait_parent_fn(alias.def_id) == self.function
607+
{
608+
// If we're lowering to associated item, install the opaque type which is just
609+
// the `type_of` of the trait's associated item. If we're using the old lowering
610+
// strategy, then just reinterpret the associated type like an opaque :^)
611+
self.tcx
612+
.type_of(alias.def_id)
613+
.instantiate(self.tcx, alias.args)
614+
.visit_with(self)?;
615+
}
616+
}
617+
ty::Alias(ty::Weak, alias) => {
618+
self.tcx
619+
.type_of(alias.def_id)
620+
.instantiate(self.tcx, alias.args)
621+
.visit_with(self)?;
622+
}
623+
_ => (),
624+
}
625+
626+
t.super_visit_with(self)
627+
}
628+
}
629+
if let ControlFlow::Break(args) =
630+
ret.visit_with(&mut Visitor { tcx, function, opaque, seen: Default::default() })
631+
{
632+
trace!(?args);
633+
trace!("expected: {hidden_ty:#?}");
634+
hidden_ty = ty::EarlyBinder::bind(hidden_ty).instantiate(tcx, args);
635+
trace!("expected: {hidden_ty:#?}");
636+
} else {
637+
tcx.sess
638+
.delay_span_bug(tcx.def_span(function), format!("{ret:?} does not contain {opaque:?}"));
639+
}
640+
Ok(hidden_ty)
641+
}
642+
472643
fn is_enum_of_nonnullable_ptr<'tcx>(
473644
tcx: TyCtxt<'tcx>,
474645
adt_def: AdtDef<'tcx>,

compiler/rustc_hir_typeck/src/callee.rs

+8
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
581581
callee_ty: Ty<'tcx>,
582582
arg_exprs: &'tcx [hir::Expr<'tcx>],
583583
) -> ErrorGuaranteed {
584+
// Callee probe fails when APIT references errors, so suppress those
585+
// errors here.
586+
if let Some((_, _, args)) = self.extract_callable_info(callee_ty)
587+
&& let Err(err) = args.error_reported()
588+
{
589+
return err;
590+
}
591+
584592
let mut unit_variant = None;
585593
if let hir::ExprKind::Path(qpath) = &callee_expr.kind
586594
&& let Res::Def(def::DefKind::Ctor(kind, CtorKind::Const), _)

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+84
Original file line numberDiff line numberDiff line change
@@ -1523,9 +1523,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15231523
found_ty: Ty<'tcx>,
15241524
expr: &hir::Expr<'_>,
15251525
) {
1526+
// When `expr` is `x` in something like `let x = foo.clone(); x`, need to recurse up to get
1527+
// `foo` and `clone`.
1528+
let expr = self.note_type_is_not_clone_inner_expr(expr);
1529+
1530+
// If we've recursed to an `expr` of `foo.clone()`, get `foo` and `clone`.
15261531
let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else {
15271532
return;
15281533
};
1534+
15291535
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else {
15301536
return;
15311537
};
@@ -1578,6 +1584,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15781584
}
15791585
}
15801586

1587+
/// Given a type mismatch error caused by `&T` being cloned instead of `T`, and
1588+
/// the `expr` as the source of this type mismatch, try to find the method call
1589+
/// as the source of this error and return that instead. Otherwise, return the
1590+
/// original expression.
1591+
fn note_type_is_not_clone_inner_expr<'b>(
1592+
&'b self,
1593+
expr: &'b hir::Expr<'b>,
1594+
) -> &'b hir::Expr<'b> {
1595+
match expr.peel_blocks().kind {
1596+
hir::ExprKind::Path(hir::QPath::Resolved(
1597+
None,
1598+
hir::Path { segments: [_], res: crate::Res::Local(binding), .. },
1599+
)) => {
1600+
let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding)
1601+
else {
1602+
return expr;
1603+
};
1604+
let Some(parent) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id)) else {
1605+
return expr;
1606+
};
1607+
1608+
match parent {
1609+
// foo.clone()
1610+
hir::Node::Local(hir::Local { init: Some(init), .. }) => {
1611+
self.note_type_is_not_clone_inner_expr(init)
1612+
}
1613+
// When `expr` is more complex like a tuple
1614+
hir::Node::Pat(hir::Pat {
1615+
hir_id: pat_hir_id,
1616+
kind: hir::PatKind::Tuple(pats, ..),
1617+
..
1618+
}) => {
1619+
let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) =
1620+
self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) else {
1621+
return expr;
1622+
};
1623+
1624+
match init.peel_blocks().kind {
1625+
ExprKind::Tup(init_tup) => {
1626+
if let Some(init) = pats
1627+
.iter()
1628+
.enumerate()
1629+
.filter(|x| x.1.hir_id == *hir_id)
1630+
.map(|(i, _)| init_tup.get(i).unwrap())
1631+
.next()
1632+
{
1633+
self.note_type_is_not_clone_inner_expr(init)
1634+
} else {
1635+
expr
1636+
}
1637+
}
1638+
_ => expr,
1639+
}
1640+
}
1641+
_ => expr,
1642+
}
1643+
}
1644+
// If we're calling into a closure that may not be typed recurse into that call. no need
1645+
// to worry if it's a call to a typed function or closure as this would ne handled
1646+
// previously.
1647+
hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => {
1648+
if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) = call_expr_kind
1649+
&& let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } = call_expr_path
1650+
&& let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding)
1651+
&& let Some(closure) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id))
1652+
&& let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure
1653+
&& let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), ..} = init
1654+
{
1655+
let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id);
1656+
self.note_type_is_not_clone_inner_expr(body_expr)
1657+
} else {
1658+
expr
1659+
}
1660+
}
1661+
_ => expr,
1662+
}
1663+
}
1664+
15811665
/// A common error is to add an extra semicolon:
15821666
///
15831667
/// ```compile_fail,E0308

0 commit comments

Comments
 (0)