Skip to content
Draft
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
14 changes: 7 additions & 7 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ use rustc_index::bit_set::DenseBitSet;
use rustc_middle::bug;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, StatementKind,
Terminator, TerminatorKind, VarBindingForm, VarDebugInfoContents,
self, AggregateKind, BindingForm, BorrowKind, CallArgumentKind, ClearCrossCrate,
ConstraintCategory, FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location,
MutBorrowKind, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement,
StatementKind, Terminator, TerminatorKind, VarBindingForm, VarDebugInfoContents,
};
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{
Expand Down Expand Up @@ -3070,7 +3070,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
name: self.synthesize_region_name(),
source: RegionNameSource::Static,
},
ConstraintCategory::CallArgument(None),
ConstraintCategory::CallArgument(None, CallArgumentKind::Normal),
var_or_use_span,
&format!("`{name}`"),
"block",
Expand All @@ -3081,7 +3081,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
) if let OutlivesConstraint {
category:
category @ (ConstraintCategory::Return(_)
| ConstraintCategory::CallArgument(_)
| ConstraintCategory::CallArgument(_, _)
| ConstraintCategory::OpaqueType),
from_closure: false,
span,
Expand Down Expand Up @@ -3719,7 +3719,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let msg = format!("{kind} is returned here");
err.span_note(constraint_span, msg);
}
ConstraintCategory::CallArgument(_) => {
ConstraintCategory::CallArgument(_, _) => {
fr_name.highlight_region_name(&mut err);
if matches!(
use_span.coroutine_kind(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
{
for constraint in path {
// If we find a call in this path, then check if it defines the opaque.
if let ConstraintCategory::CallArgument(Some(call_ty)) = constraint.category
if let ConstraintCategory::CallArgument(Some(call_ty), _) = constraint.category
&& let ty::FnDef(call_def_id, _) = *call_ty.kind()
// This function defines the opaque :D
&& call_def_id == parent
Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
use rustc_infer::infer::{NllRegionVariableOrigin, SubregionOrigin};
use rustc_middle::bug;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
use rustc_middle::mir::{AnnotationSource, CallArgumentKind, ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::{
self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions,
};
Expand Down Expand Up @@ -49,7 +49,11 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
ConstraintCategory::UseAsStatic => "using this value as a static ",
ConstraintCategory::Cast { is_implicit_coercion: false, .. } => "cast ",
ConstraintCategory::Cast { is_implicit_coercion: true, .. } => "coercion ",
ConstraintCategory::CallArgument(_) => "argument ",
ConstraintCategory::CallArgument(_, kind) => match kind {
CallArgumentKind::Normal => "argument ",
CallArgumentKind::Receiver => "receiver ",
CallArgumentKind::Closure => "closure ",
},
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => "generic argument ",
ConstraintCategory::TypeAnnotation(_) => "type annotation ",
ConstraintCategory::SizedBound => "proving this value is `Sized` ",
Expand Down Expand Up @@ -491,7 +495,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.report_fnmut_error(&errci, kind)
}
(ConstraintCategory::Assignment, true, false)
| (ConstraintCategory::CallArgument(_), true, false) => {
| (ConstraintCategory::CallArgument(_, _), true, false) => {
let mut db = self.report_escaping_data_error(&errci);

outlives_suggestion.intermediate_suggestion(self, &errci, &mut db);
Expand Down Expand Up @@ -945,7 +949,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {

let tcx = self.infcx.tcx;

let ConstraintCategory::CallArgument(Some(func_ty)) = category else { return };
let ConstraintCategory::CallArgument(Some(func_ty), _) = category else { return };
let ty::FnDef(fn_did, args) = *func_ty.kind() else { return };
debug!(?fn_did, ?args);

Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,6 @@ pub struct ClosureOutlivesRequirement<'tcx> {
pub category: ConstraintCategory<'tcx>,
}

// Make sure this enum doesn't unintentionally grow
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);

/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
/// that must outlive some region.
#[derive(Copy, Clone, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1754,7 +1754,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
| AnnotationSource::OpaqueCast,
)
| ConstraintCategory::Cast { .. }
| ConstraintCategory::CallArgument(_)
| ConstraintCategory::CallArgument(_, _)
| ConstraintCategory::CopyBound
| ConstraintCategory::SizedBound
| ConstraintCategory::Assignment
Expand Down
59 changes: 48 additions & 11 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::lang_items::{FN_TRAITS, LangItem};
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
Expand Down Expand Up @@ -438,6 +438,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.relate_types(sup, ty::Contravariant, sub, locations, category)
}

fn sub_types_spanned(
&mut self,
sub: Ty<'tcx>,
sup: Ty<'tcx>,
locations: Locations,
span: Option<Span>,
category: ConstraintCategory<'tcx>,
) -> Result<(), NoSolution> {
// Use this order of parameters because the sup type is usually the
// "expected" type in diagnostics.
self.relate_types_spanned(sup, ty::Contravariant, sub, locations, span, category)
}

#[instrument(skip(self, category), level = "debug")]
fn eq_types(
&mut self,
Expand Down Expand Up @@ -1630,7 +1643,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ty_left,
common_ty,
location.to_locations(),
ConstraintCategory::CallArgument(None),
ConstraintCategory::CallArgument(None, CallArgumentKind::Normal),
)
.unwrap_or_else(|err| {
bug!("Could not equate type variable with {:?}: {:?}", ty_left, err)
Expand All @@ -1639,7 +1652,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ty_right,
common_ty,
location.to_locations(),
ConstraintCategory::CallArgument(None),
ConstraintCategory::CallArgument(None, CallArgumentKind::Normal),
) {
span_mirbug!(
self,
Expand Down Expand Up @@ -2047,16 +2060,40 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let op_arg_ty = op_arg.node.ty(self.body, self.tcx());

let op_arg_ty = self.normalize(ty::Unnormalized::new_wip(op_arg_ty), term_location);
let category = if call_source.from_hir_call() {
ConstraintCategory::CallArgument(Some(
self.infcx.tcx.erase_and_anonymize_regions(func_ty),
))
let is_closure = n == 0
&& matches!(func_ty.kind(), ty::FnDef(def_id, _) if {
let tcx = self.tcx();
let trait_id = tcx.trait_item_of(*def_id).unwrap_or(*def_id);
tcx.trait_of_assoc(trait_id).is_some_and(|trait_id| {
FN_TRAITS.iter().any(|&lang_item| tcx.is_lang_item(trait_id, lang_item))
})
});
let is_receiver = n == 0
&& matches!(&term.kind, TerminatorKind::Call { fn_span, .. } if term.source_info.span != *fn_span);
let (category, span) = if call_source.from_hir_call() {
(
ConstraintCategory::CallArgument(
Some(self.infcx.tcx.erase_and_anonymize_regions(func_ty)),
if is_closure {
CallArgumentKind::Closure
} else if is_receiver {
CallArgumentKind::Receiver
} else {
CallArgumentKind::Normal
},
),
Some(op_arg.span),
)
} else {
ConstraintCategory::Boring
(ConstraintCategory::Boring, None)
};
if let Err(terr) =
self.sub_types(op_arg_ty, *fn_arg, term_location.to_locations(), category)
{
if let Err(terr) = self.sub_types_spanned(
op_arg_ty,
*fn_arg,
term_location.to_locations(),
span,
category,
) {
span_mirbug!(
self,
term,
Expand Down
28 changes: 24 additions & 4 deletions compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ use crate::renumber::RegionCtxt;
use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
pub(super) fn relate_types(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
) -> Result<(), NoSolution> {
self.relate_types_spanned(a, v, b, locations, None, category)
}

/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
///
/// - "Covariant" `a <: b`
Expand All @@ -31,16 +42,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
///
/// N.B., the type `a` is permitted to have unresolved inference
/// variables, but not the type `b`.
///
/// FIXME: Explain `span`
#[instrument(skip(self), level = "debug")]
pub(super) fn relate_types(
pub(super) fn relate_types_spanned(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
span: Option<Span>,
category: ConstraintCategory<'tcx>,
) -> Result<(), NoSolution> {
NllTypeRelating::new(self, locations, category, UniverseInfo::relate(a, b), v)
NllTypeRelating::new(self, locations, span, category, UniverseInfo::relate(a, b), v)
.relate(a, b)?;
Ok(())
}
Expand All @@ -53,7 +67,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
locations: Locations,
category: ConstraintCategory<'tcx>,
) -> Result<(), NoSolution> {
NllTypeRelating::new(self, locations, category, UniverseInfo::other(), ty::Invariant)
NllTypeRelating::new(self, locations, None, category, UniverseInfo::other(), ty::Invariant)
.relate(a, b)?;
Ok(())
}
Expand All @@ -65,6 +79,10 @@ struct NllTypeRelating<'a, 'b, 'tcx> {
/// Where (and why) is this relation taking place?
locations: Locations,

/// An optional Span in case we want to be more specific than `locations` in
/// diagnostics.
span: Option<Span>,

/// What category do we assign the resulting `'a: 'b` relationships?
category: ConstraintCategory<'tcx>,

Expand All @@ -87,6 +105,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
fn new(
type_checker: &'a mut TypeChecker<'b, 'tcx>,
locations: Locations,
span: Option<Span>,
category: ConstraintCategory<'tcx>,
universe_info: UniverseInfo<'tcx>,
ambient_variance: ty::Variance,
Expand All @@ -97,6 +116,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
category,
universe_info,
ambient_variance,
span,
ambient_variance_info: ty::VarianceDiagInfo::default(),
}
}
Expand Down Expand Up @@ -299,7 +319,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
sup,
sub,
locations: self.locations,
span: self.locations.span(self.type_checker.body),
span: self.span.unwrap_or_else(|| self.locations.span(self.type_checker.body)),
category: self.category,
variance_info: info,
from_closure: false,
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,19 @@ pub struct ConstQualifs {
pub needs_non_const_drop: bool,
pub tainted_by_errors: Option<ErrorGuaranteed>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(TyEncodable, TyDecodable, StableHash, TypeVisitable, TypeFoldable)]
pub enum CallArgumentKind {
Normal,
Receiver,
Closure,
}

// Make sure this enum doesn't unintentionally grow
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);

/// Outlives-constraints can be categorized to determine whether and why they
/// are interesting (for error reporting). Order of variants indicates sort
/// order of the category, thereby influencing diagnostic output.
Expand All @@ -116,7 +129,7 @@ pub enum ConstraintCategory<'tcx> {
},

/// Contains the function type if available.
CallArgument(Option<Ty<'tcx>>),
CallArgument(Option<Ty<'tcx>>, CallArgumentKind), // to save binary size for static_assert_size!
CopyBound,
SizedBound,
Assignment,
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/tests/ui/crashes/ice-6256.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ error[E0521]: borrowed data escapes outside of closure
--> tests/ui/crashes/ice-6256.rs:13:26
|
LL | let f = |x: &dyn TT| x.func();
| - - ^^^^^^^^
| - - ^
| | | |
| | | `x` escapes the closure body here
| | | argument requires that `'1` must outlive `'static`
| | | receiver requires that `'1` must outlive `'static`
| | let's call the lifetime of this reference `'1`
| `x` is a reference that is only valid in the closure body

Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:40:13
--> $DIR/project-fn-ret-invariant.rs:40:20
|
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
LL | let a = bar(f, x);
| ^^^^^^^^^ argument requires that `'b` must outlive `'a`
| ^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
= note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant
= note: the struct `Type<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:42:13
--> $DIR/project-fn-ret-invariant.rs:42:20
|
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let b = bar(f, y);
| ^^^^^^^^^ argument requires that `'a` must outlive `'b`
| ^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
= note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant
Expand Down
Loading
Loading