Auto merge of #107400 - matthiaskrgr:rollup-l6bycds, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #107022 (Implement `SpecOptionPartialEq` for `cmp::Ordering`)
 - #107100 (Use proper `InferCtxt` when probing for associated types in astconv)
 - #107103 (Use new solver in `evaluate_obligation` query (when new solver is enabled))
 - #107190 (Recover from more const arguments that are not wrapped in curly braces)
 - #107306 (Correct suggestions for closure arguments that need a borrow)
 - #107339 (internally change regions to be covariant)
 - #107344 (Minor tweaks in the new solver)
 - #107373 (Don't merge vtables when full debuginfo is enabled.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-01-28 06:46:42 +00:00
commit 226b2496fc
39 changed files with 531 additions and 160 deletions

View file

@ -1499,6 +1499,11 @@ pub fn create_vtable_di_node<'ll, 'tcx>(
return;
}
// When full debuginfo is enabled, we want to try and prevent vtables from being
// merged. Otherwise debuggers will have a hard time mapping from dyn pointer
// to concrete type.
llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No);
let vtable_name =
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref);

View file

@ -27,7 +27,7 @@
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
@ -37,7 +37,7 @@
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, Span};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations;
@ -54,7 +54,7 @@
pub struct PathSeg(pub DefId, pub usize);
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn tcx(&self) -> TyCtxt<'tcx>;
fn item_def_id(&self) -> DefId;
@ -131,6 +131,8 @@ fn astconv(&self) -> &dyn AstConv<'tcx>
{
self
}
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
}
#[derive(Debug)]
@ -2132,48 +2134,8 @@ pub fn associated_path_to_ty(
)
.emit() // Already reported in an earlier stage.
} else {
// Find all the `impl`s that `qself_ty` has for any trait that has the
// associated type, so that we suggest the right one.
let infcx = tcx.infer_ctxt().build();
// We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
// to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
let param_env = ty::ParamEnv::empty();
let traits: Vec<_> = self
.tcx()
.all_traits()
.filter(|trait_def_id| {
// Consider only traits with the associated type
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type)
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
.is_accessible_from(self.item_def_id(), tcx)
&& tcx.all_impls(*trait_def_id)
.any(|impl_def_id| {
let trait_ref = tcx.impl_trait_ref(impl_def_id);
trait_ref.map_or(false, |trait_ref| {
let impl_ = trait_ref.subst(
tcx,
infcx.fresh_substs_for_item(span, impl_def_id),
);
infcx
.can_eq(
param_env,
tcx.erase_regions(impl_.self_ty()),
tcx.erase_regions(qself_ty),
)
.is_ok()
})
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
})
})
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
.collect();
let traits: Vec<_> =
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
// Don't print `TyErr` to the user.
self.report_ambiguous_associated_type(
@ -2232,6 +2194,60 @@ pub fn associated_path_to_ty(
Ok((ty, DefKind::AssocTy, assoc_ty_did))
}
fn probe_traits_that_match_assoc_ty(
&self,
qself_ty: Ty<'tcx>,
assoc_ident: Ident,
) -> Vec<String> {
let tcx = self.tcx();
// In contexts that have no inference context, just make a new one.
// We do need a local variable to store it, though.
let infcx_;
let infcx = if let Some(infcx) = self.infcx() {
infcx
} else {
assert!(!qself_ty.needs_infer());
infcx_ = tcx.infer_ctxt().build();
&infcx_
};
tcx.all_traits()
.filter(|trait_def_id| {
// Consider only traits with the associated type
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type)
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
.is_accessible_from(self.item_def_id(), tcx)
&& tcx.all_impls(*trait_def_id)
.any(|impl_def_id| {
let trait_ref = tcx.impl_trait_ref(impl_def_id);
trait_ref.map_or(false, |trait_ref| {
let impl_ = trait_ref.subst(
tcx,
infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
);
infcx
.can_eq(
ty::ParamEnv::empty(),
tcx.erase_regions(impl_.self_ty()),
tcx.erase_regions(qself_ty),
)
.is_ok()
})
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
})
})
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
.collect()
}
fn lookup_assoc_ty(
&self,
ident: Ident,

View file

@ -25,7 +25,7 @@
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::query::Providers;
@ -517,6 +517,10 @@ fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
// There's no place to record types from signatures?
}
fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
None
}
}
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.

View file

@ -225,8 +225,7 @@ fn add_constraints_from_ty(
}
ty::Ref(region, ty, mutbl) => {
let contra = self.contravariant(variance);
self.add_constraints_from_region(current, region, contra);
self.add_constraints_from_region(current, region, variance);
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
}
@ -258,9 +257,8 @@ fn add_constraints_from_ty(
}
ty::Dynamic(data, r, _) => {
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
let contra = self.contravariant(variance);
self.add_constraints_from_region(current, r, contra);
// The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
self.add_constraints_from_region(current, r, variance);
if let Some(poly_trait_ref) = data.principal() {
self.add_constraints_from_invariant_substs(

View file

@ -324,6 +324,10 @@ fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
self.write_ty(hir_id, ty)
}
fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
Some(&self.infcx)
}
}
/// Represents a user-provided type in the raw form (never normalized).

View file

@ -79,7 +79,8 @@ fn regions(
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
let origin = Subtype(Box::new(self.fields.trace.clone()));
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
// GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
self.tcx(),
origin,
a,

View file

@ -79,7 +79,8 @@ fn regions(
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
let origin = Subtype(Box::new(self.fields.trace.clone()));
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
// LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
self.tcx(),
origin,
a,

View file

@ -663,13 +663,13 @@ fn regions(
debug!(?v_b);
if self.ambient_covariance() {
// Covariance: a <= b. Hence, `b: a`.
self.push_outlives(v_b, v_a, self.ambient_variance_info);
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
self.push_outlives(v_a, v_b, self.ambient_variance_info);
}
if self.ambient_contravariance() {
// Contravariant: b <= a. Hence, `a: b`.
self.push_outlives(v_a, v_b, self.ambient_variance_info);
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
self.push_outlives(v_b, v_a, self.ambient_variance_info);
}
Ok(a)

View file

@ -191,12 +191,13 @@ fn regions(
// from the "cause" field, we could perhaps give more tailored
// error messages.
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
self.fields
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_subregion(origin, a, b);
.make_subregion(origin, b, a);
Ok(a)
}

View file

@ -443,12 +443,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
if a_repr == b_repr =>
{
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
relation.relate_with_variance(
ty::Contravariant,
ty::VarianceDiagInfo::default(),
a_region,
b_region,
)
relation.relate(a_region, b_region)
})?;
Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr))
}
@ -497,12 +492,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
}
(&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
let r = relation.relate_with_variance(
ty::Contravariant,
ty::VarianceDiagInfo::default(),
a_r,
b_r,
)?;
let r = relation.relate(a_r, b_r)?;
let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;

View file

@ -2353,6 +2353,28 @@ pub fn recover_const_arg(
Err(err)
}
/// Try to recover from an unbraced const argument whose first token [could begin a type][ty].
///
/// [ty]: token::Token::can_begin_type
pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
&mut self,
mut snapshot: SnapshotParser<'a>,
) -> Option<P<ast::Expr>> {
match snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) {
// Since we don't know the exact reason why we failed to parse the type or the
// expression, employ a simple heuristic to weed out some pathological cases.
Ok(expr) if let token::Comma | token::Gt = snapshot.token.kind => {
self.restore_snapshot(snapshot);
Some(expr)
}
Ok(_) => None,
Err(err) => {
err.cancel();
None
}
}
}
/// Creates a dummy const argument, and reports that the expression must be enclosed in braces
pub fn dummy_const_arg_needs_braces(
&self,

View file

@ -675,22 +675,42 @@ pub(super) fn parse_generic_arg(
GenericArg::Const(self.parse_const_arg()?)
} else if self.check_type() {
// Parse type argument.
let is_const_fn =
self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis));
let mut snapshot = self.create_snapshot_for_diagnostic();
// Proactively create a parser snapshot enabling us to rewind and try to reparse the
// input as a const expression in case we fail to parse a type. If we successfully
// do so, we will report an error that it needs to be wrapped in braces.
let mut snapshot = None;
if self.may_recover() && self.token.can_begin_expr() {
snapshot = Some(self.create_snapshot_for_diagnostic());
}
match self.parse_ty() {
Ok(ty) => GenericArg::Type(ty),
Ok(ty) => {
// Since the type parser recovers from some malformed slice and array types and
// successfully returns a type, we need to look for `TyKind::Err`s in the
// type to determine if error recovery has occurred and if the input is not a
// syntactically valid type after all.
if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind
&& let ast::TyKind::Err = inner_ty.kind
&& let Some(snapshot) = snapshot
&& let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
{
return Ok(Some(self.dummy_const_arg_needs_braces(
self.struct_span_err(expr.span, "invalid const generic expression"),
expr.span,
)));
}
GenericArg::Type(ty)
}
Err(err) => {
if is_const_fn {
match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) {
Ok(expr) => {
self.restore_snapshot(snapshot);
return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
}
Err(err) => {
err.cancel();
}
}
if let Some(snapshot) = snapshot
&& let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
{
return Ok(Some(self.dummy_const_arg_needs_braces(
err,
expr.span,
)));
}
// Try to recover from possible `const` arg without braces.
return self.recover_const_arg(start, err).map(Some);

View file

@ -1,6 +1,8 @@
//! Code shared by trait and projection goals for candidate assembly.
use super::infcx_ext::InferCtxtExt;
#[cfg(doc)]
use super::trait_goals::structural_traits::*;
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution;
@ -98,52 +100,75 @@ fn consider_assumption(
assumption: ty::Predicate<'tcx>,
) -> QueryResult<'tcx>;
// A type implements an `auto trait` if its components do as well. These components
// are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`].
fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// A trait alias holds if the RHS traits and `where` clauses hold.
fn consider_trait_alias_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// A type is `Copy` or `Clone` if its components are `Sized`. These components
// are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`].
fn consider_builtin_sized_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These
// components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`].
fn consider_builtin_copy_clone_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// A type is `PointerSized` if we can compute its layout, and that layout
// matches the layout of `usize`.
fn consider_builtin_pointer_sized_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
// family of traits where `A` is given by the signature of the type.
fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
kind: ty::ClosureKind,
) -> QueryResult<'tcx>;
// `Tuple` is implemented if the `Self` type is a tuple.
fn consider_builtin_tuple_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// `Pointee` is always implemented.
//
// See the projection implementation for the `Metadata` types for all of
// the built-in types. For structs, the metadata type is given by the struct
// tail.
fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// A generator (that comes from an `async` desugaring) is known to implement
// `Future<Output = O>`, where `O` is given by the generator's return type
// that was computed during type-checking.
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
// A generator (that doesn't come from an `async` desugaring) is known to
// implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield,
// and return types of the generator computed during type-checking.
fn consider_builtin_generator_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,

View file

@ -335,15 +335,13 @@ fn compute_subtype_goal(
// That won't actually reflect in the query response, so it seems moot.
self.make_canonical_response(Certainty::AMBIGUOUS)
} else {
self.infcx.probe(|_| {
let InferOk { value: (), obligations } = self
.infcx
.at(&ObligationCause::dummy(), goal.param_env)
.sub(goal.predicate.a, goal.predicate.b)?;
self.evaluate_all_and_make_canonical_response(
obligations.into_iter().map(|pred| pred.into()).collect(),
)
})
let InferOk { value: (), obligations } = self
.infcx
.at(&ObligationCause::dummy(), goal.param_env)
.sub(goal.predicate.a, goal.predicate.b)?;
self.evaluate_all_and_make_canonical_response(
obligations.into_iter().map(|pred| pred.into()).collect(),
)
}
}
@ -376,22 +374,22 @@ fn compute_well_formed_goal(
&mut self,
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
) -> QueryResult<'tcx> {
self.infcx.probe(|_| {
match crate::traits::wf::unnormalized_obligations(
self.infcx,
goal.param_env,
goal.predicate,
) {
Some(obligations) => self.evaluate_all_and_make_canonical_response(
obligations.into_iter().map(|o| o.into()).collect(),
),
None => self.make_canonical_response(Certainty::AMBIGUOUS),
}
})
match crate::traits::wf::unnormalized_obligations(
self.infcx,
goal.param_env,
goal.predicate,
) {
Some(obligations) => self.evaluate_all_and_make_canonical_response(
obligations.into_iter().map(|o| o.into()).collect(),
),
None => self.make_canonical_response(Certainty::AMBIGUOUS),
}
}
}
impl<'tcx> EvalCtxt<'_, 'tcx> {
// Recursively evaluates a list of goals to completion, returning the certainty
// of all of the goals.
fn evaluate_all(
&mut self,
mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
@ -428,6 +426,10 @@ fn evaluate_all(
})
}
// Recursively evaluates a list of goals to completion, making a query response.
//
// This is just a convenient way of calling [`EvalCtxt::evaluate_all`],
// then [`EvalCtxt::make_canonical_response`].
fn evaluate_all_and_make_canonical_response(
&mut self,
goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,

View file

@ -296,7 +296,9 @@ fn consider_assumption(
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
{
ecx.infcx.probe(|_| {
let assumption_projection_pred =
ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);

View file

@ -65,7 +65,9 @@ fn consider_assumption(
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() {
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
&& poly_trait_pred.def_id() == goal.predicate.def_id()
{
// FIXME: Constness and polarity
ecx.infcx.probe(|_| {
let assumption_trait_pred =

View file

@ -3807,13 +3807,13 @@ fn hint_missing_borrow<'tcx>(
err: &mut Diagnostic,
) {
let found_args = match found.kind() {
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
kind => {
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
}
};
let expected_args = match expected.kind() {
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
kind => {
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
}
@ -3824,12 +3824,12 @@ fn hint_missing_borrow<'tcx>(
let args = fn_decl.inputs.iter().map(|ty| ty);
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
let mut refs = 0;
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
let mut refs = vec![];
while let ty::Ref(_, new_ty, _) = ty.kind() {
while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
ty = *new_ty;
refs += 1;
refs.push(*mutbl);
}
(ty, refs)
@ -3843,11 +3843,21 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
if found_refs < expected_refs {
to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
} else if found_refs > expected_refs {
// FIXME: This could handle more exotic cases like mutability mismatches too!
if found_refs.len() < expected_refs.len()
&& found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
{
to_borrow.push((
arg.span.shrink_to_lo(),
expected_refs[..expected_refs.len() - found_refs.len()]
.iter()
.map(|mutbl| format!("&{}", mutbl.prefix_str()))
.collect::<Vec<_>>()
.join(""),
));
} else if found_refs.len() > expected_refs.len() {
let mut span = arg.span.shrink_to_lo();
let mut left = found_refs - expected_refs;
let mut left = found_refs.len() - expected_refs.len();
let mut ty = arg;
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
span = span.with_hi(mut_ty.ty.span.lo());

View file

@ -1,7 +1,9 @@
use rustc_middle::ty;
use rustc_session::config::TraitSolver;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::InferCtxt;
use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause};
use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
pub trait InferCtxtExt<'tcx> {
@ -77,12 +79,38 @@ fn evaluate_obligation(
_ => obligation.param_env.without_const(),
};
let c_pred = self
.canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
// Run canonical query. If overflow occurs, rerun from scratch but this time
// in standard trait query mode so that overflow is handled appropriately
// within `SelectionContext`.
self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
let c_pred = self.canonicalize_query_keep_static(
param_env.and(obligation.predicate),
&mut _orig_values,
);
self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
} else {
self.probe(|snapshot| {
if let Ok((_, certainty)) =
self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate))
{
match certainty {
Certainty::Yes => {
if self.opaque_types_added_in_snapshot(snapshot) {
Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
} else if self.region_constraints_added_in_snapshot(snapshot).is_some()
{
Ok(EvaluationResult::EvaluatedToOkModuloRegions)
} else {
Ok(EvaluationResult::EvaluatedToOk)
}
}
Certainty::Maybe(MaybeCause::Ambiguity) => {
Ok(EvaluationResult::EvaluatedToAmbig)
}
Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical),
}
} else {
Ok(EvaluationResult::EvaluatedToErr)
}
})
}
}
// Helper function that canonicalizes and runs the query. If an
@ -92,6 +120,9 @@ fn evaluate_obligation_no_overflow(
&self,
obligation: &PredicateObligation<'tcx>,
) -> EvaluationResult {
// Run canonical query. If overflow occurs, rerun from scratch but this time
// in standard trait query mode so that overflow is handled appropriately
// within `SelectionContext`.
match self.evaluate_obligation(obligation) {
Ok(result) => result,
Err(OverflowError::Canonical) => {

View file

@ -551,7 +551,7 @@
use crate::panicking::{panic, panic_str};
use crate::pin::Pin;
use crate::{
convert, hint, mem,
cmp, convert, hint, mem,
ops::{self, ControlFlow, Deref, DerefMut},
};
@ -2090,6 +2090,12 @@ fn eq(&self, other: &Self) -> bool {
}
}
/// This specialization trait is a workaround for LLVM not currently (2023-01)
/// being able to optimize this itself, even though Alive confirms that it would
/// be legal to do so: <https://github.com/llvm/llvm-project/issues/52622>
///
/// Once that's fixed, `Option` should go back to deriving `PartialEq`, as
/// it used to do before <https://github.com/rust-lang/rust/pull/103556>.
#[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")]
#[doc(hidden)]
pub trait SpecOptionPartialEq: Sized {
@ -2146,6 +2152,14 @@ fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl SpecOptionPartialEq for cmp::Ordering {
#[inline]
fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
l.map_or(2, |x| x as i8) == r.map_or(2, |x| x as i8)
}
}
/////////////////////////////////////////////////////////////////////////////
// The Option Iterators
/////////////////////////////////////////////////////////////////////////////

View file

@ -9,6 +9,14 @@
// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
// ignore-tidy-linelength
// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
// This helps debuggers more reliably map from dyn pointer to concrete type.
// CHECK: @vtable.0 = private constant <{
// CHECK: @vtable.1 = private constant <{
// CHECK: @vtable.2 = private constant <{
// CHECK: @vtable.3 = private constant <{
// CHECK: @vtable.4 = private constant <{
// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize"
// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize"
// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"

View file

@ -3,6 +3,7 @@
#![crate_type = "lib"]
extern crate core;
use core::cmp::Ordering;
use core::num::{NonZeroU32, NonZeroI64};
use core::ptr::NonNull;
@ -32,3 +33,12 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
// CHECK-NEXT: ret i1
l == r
}
// CHECK-lABEL: @ordering_eq
#[no_mangle]
pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
// CHECK: start:
// CHECK-NEXT: icmp eq i8
// CHECK-NEXT: ret i1
l == r
}

View file

@ -13,10 +13,34 @@ fn main() {
let _: Wow<A.0>;
//~^ ERROR expected one of
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
// FIXME(compiler-errors): This one is still unsatisfying,
// and probably a case I could see someone typing by accident..
let _: Wow<[]>;
//~^ ERROR expected type
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<[12]>;
//~^ ERROR expected type, found
//~| ERROR type provided when a constant was expected
//~^ ERROR expected type
//~| ERROR invalid const generic expression
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<[0, 1, 3]>;
//~^ ERROR expected type
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<[0xff; 8]>;
//~^ ERROR expected type
//~| ERROR invalid const generic expression
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<[1, 2]>; // Regression test for issue #81698.
//~^ ERROR expected type
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<&0>;
//~^ ERROR expected type
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<("", 0)>;
//~^ ERROR expected type
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<(1 + 2) * 3>;
//~^ ERROR expected type
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
// FIXME(fmease): This one is pretty bad.
let _: Wow<!0>;
//~^ ERROR expected one of
//~| HELP you might have meant to end the type parameters here
}

View file

@ -42,18 +42,118 @@ help: expressions must be enclosed in braces to be used as const generic argumen
LL | let _: Wow<{ A.0 }>;
| + +
error: expected type, found `]`
--> $DIR/bad-const-generic-exprs.rs:16:17
|
LL | let _: Wow<[]>;
| ^ expected type
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ [] }>;
| + +
error: expected type, found `12`
--> $DIR/bad-const-generic-exprs.rs:19:17
|
LL | let _: Wow<[12]>;
| ^^ expected type
error[E0747]: type provided when a constant was expected
error: invalid const generic expression
--> $DIR/bad-const-generic-exprs.rs:19:16
|
LL | let _: Wow<[12]>;
| ^^^^
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ [12] }>;
| + +
error: aborting due to 6 previous errors
error: expected type, found `0`
--> $DIR/bad-const-generic-exprs.rs:23:17
|
LL | let _: Wow<[0, 1, 3]>;
| ^ expected type
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ [0, 1, 3] }>;
| + +
error: expected type, found `0xff`
--> $DIR/bad-const-generic-exprs.rs:26:17
|
LL | let _: Wow<[0xff; 8]>;
| ^^^^ expected type
error: invalid const generic expression
--> $DIR/bad-const-generic-exprs.rs:26:16
|
LL | let _: Wow<[0xff; 8]>;
| ^^^^^^^^^
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ [0xff; 8] }>;
| + +
error: expected type, found `1`
--> $DIR/bad-const-generic-exprs.rs:30:17
|
LL | let _: Wow<[1, 2]>; // Regression test for issue #81698.
| ^ expected type
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ [1, 2] }>; // Regression test for issue #81698.
| + +
error: expected type, found `0`
--> $DIR/bad-const-generic-exprs.rs:33:17
|
LL | let _: Wow<&0>;
| ^ expected type
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ &0 }>;
| + +
error: expected type, found `""`
--> $DIR/bad-const-generic-exprs.rs:36:17
|
LL | let _: Wow<("", 0)>;
| ^^ expected type
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ ("", 0) }>;
| + +
error: expected type, found `1`
--> $DIR/bad-const-generic-exprs.rs:39:17
|
LL | let _: Wow<(1 + 2) * 3>;
| ^ expected type
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ (1 + 2) * 3 }>;
| + +
error: expected one of `,` or `>`, found `0`
--> $DIR/bad-const-generic-exprs.rs:43:17
|
LL | let _: Wow<!0>;
| - ^ expected one of `,` or `>`
| |
| while parsing the type for `_`
|
help: you might have meant to end the type parameters here
|
LL | let _: Wow<!>0>;
| +
error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0747`.

View file

@ -1,7 +1,7 @@
#![feature(rustc_attrs)]
#[rustc_variance]
struct Foo<'a, T> { //~ ERROR [-, o]
struct Foo<'a, T> { //~ ERROR [+, o]
t: &'a mut T,
}

View file

@ -1,4 +1,4 @@
error: [-, o]
error: [+, o]
--> $DIR/E0208.rs:4:1
|
LL | struct Foo<'a, T> {

View file

@ -0,0 +1,28 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
pub struct Trader<'a> {
closure: Box<dyn Fn(&mut Trader) + 'a>,
}
impl<'a> Trader<'a> {
pub fn new() -> Self {
Trader {
closure: Box::new(|_| {}),
}
}
pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
//foo
}
}
fn main() {
let closure = |trader : Trader| {
println!("Woooosh!");
};
let mut trader = Trader::new();
trader.set_closure(closure);
//~^ ERROR type mismatch in closure arguments
}

View file

@ -0,0 +1,26 @@
error[E0631]: type mismatch in closure arguments
--> $DIR/late-bound-in-borrow-closure-sugg.rs:26:24
|
LL | let closure = |trader : Trader| {
| ----------------- found signature defined here
...
LL | trader.set_closure(closure);
| ----------- ^^^^^^^ expected due to this
| |
| required by a bound introduced by this call
|
= note: expected closure signature `for<'a, 'b> fn(&'a mut Trader<'b>) -> _`
found closure signature `for<'a> fn(Trader<'a>) -> _`
note: required by a bound in `Trader::<'a>::set_closure`
--> $DIR/late-bound-in-borrow-closure-sugg.rs:15:50
|
LL | pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
| ^^^^^^^^^^^^^^^ required by this bound in `Trader::<'a>::set_closure`
help: consider borrowing the argument
|
LL | let closure = |trader : &mut Trader| {
| ++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0631`.

View file

@ -0,0 +1,18 @@
struct A<T>(T);
trait Foo {
type B;
}
impl Foo for A<u32> {
type B = i32;
}
impl Foo for A<i32> {
type B = i32;
}
fn main() {
A::B::<>::C
//~^ ERROR ambiguous associated type
}

View file

@ -0,0 +1,9 @@
error[E0223]: ambiguous associated type
--> $DIR/issue-107087.rs:16:5
|
LL | A::B::<>::C
| ^^^^^^^^ help: use the fully-qualified path: `<A<_> as Foo>::B`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0223`.

View file

@ -10,7 +10,7 @@ fn method(&'a self) { }
}
#[rustc_variance]
struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +]
field: (T, &'a ())
}

View file

@ -1,4 +1,4 @@
error: [-, +]
error: [+, +]
--> $DIR/variance-associated-types.rs:13:1
|
LL | struct Foo<'a, T : Trait<'a>> {

View file

@ -6,7 +6,7 @@
// Regions that just appear in normal spots are contravariant:
#[rustc_variance]
struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +]
x: &'a isize,
y: &'b [isize],
c: &'c str
@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
// Those same annotations in function arguments become covariant:
#[rustc_variance]
struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -]
x: extern "Rust" fn(&'a isize),
y: extern "Rust" fn(&'b [isize]),
c: extern "Rust" fn(&'c str),
@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
// Mutability induces invariance:
#[rustc_variance]
struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
struct Test4<'a, 'b:'a> { //~ ERROR [+, o]
x: &'a mut &'b isize,
}
@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
// contravariant context:
#[rustc_variance]
struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
struct Test5<'a, 'b:'a> { //~ ERROR [-, o]
x: extern "Rust" fn(&'a mut &'b isize),
}
@ -42,7 +42,7 @@ struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
// argument list occurs in an invariant context.
#[rustc_variance]
struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
struct Test6<'a, 'b:'a> { //~ ERROR [+, o]
x: &'a mut extern "Rust" fn(&'b isize),
}
@ -56,7 +56,7 @@ struct Test7<'a> { //~ ERROR [*]
// Try enums too.
#[rustc_variance]
enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
Test8A(extern "Rust" fn(&'a isize)),
Test8B(&'b [isize]),
Test8C(&'b mut &'c str),

View file

@ -1,28 +1,28 @@
error: [-, -, -]
error: [+, +, +]
--> $DIR/variance-regions-direct.rs:9:1
|
LL | struct Test2<'a, 'b, 'c> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: [+, +, +]
error: [-, -, -]
--> $DIR/variance-regions-direct.rs:18:1
|
LL | struct Test3<'a, 'b, 'c> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: [-, o]
error: [+, o]
--> $DIR/variance-regions-direct.rs:27:1
|
LL | struct Test4<'a, 'b:'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^
error: [+, o]
error: [-, o]
--> $DIR/variance-regions-direct.rs:35:1
|
LL | struct Test5<'a, 'b:'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^
error: [-, o]
error: [+, o]
--> $DIR/variance-regions-direct.rs:45:1
|
LL | struct Test6<'a, 'b:'a> {
@ -34,7 +34,7 @@ error: [*]
LL | struct Test7<'a> {
| ^^^^^^^^^^^^^^^^
error: [+, -, o]
error: [-, +, o]
--> $DIR/variance-regions-direct.rs:59:1
|
LL | enum Test8<'a, 'b, 'c:'b> {

View file

@ -5,14 +5,14 @@
#![feature(rustc_attrs)]
#[rustc_variance]
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *]
Test8A(extern "Rust" fn(&'a isize)),
Test8B(&'b [isize]),
Test8C(&'b mut &'c str),
}
#[rustc_variance]
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -]
f: Base<'z, 'y, 'x, 'w>
}
@ -22,12 +22,12 @@ struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
}
#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *]
f: Base<'a, 'b, 'a, 'c>
}
#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
f: Base<'a, 'b, 'c, 'a>
}

View file

@ -1,10 +1,10 @@
error: [+, -, o, *]
error: [-, +, o, *]
--> $DIR/variance-regions-indirect.rs:8:1
|
LL | enum Base<'a, 'b, 'c:'b, 'd> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: [*, o, -, +]
error: [*, o, +, -]
--> $DIR/variance-regions-indirect.rs:15:1
|
LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
@ -16,13 +16,13 @@ error: [o, o, *]
LL | struct Derived2<'a, 'b:'a, 'c> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: [o, -, *]
error: [o, +, *]
--> $DIR/variance-regions-indirect.rs:25:1
|
LL | struct Derived3<'a:'b, 'b, 'c> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: [+, -, o]
error: [-, +, o]
--> $DIR/variance-regions-indirect.rs:30:1
|
LL | struct Derived4<'a, 'b, 'c:'b> {

View file

@ -11,7 +11,7 @@
trait T { fn foo(&self); }
#[rustc_variance]
struct TOption<'a> { //~ ERROR [-]
struct TOption<'a> { //~ ERROR [+]
v: Option<Box<dyn T + 'a>>,
}

View file

@ -1,4 +1,4 @@
error: [-]
error: [+]
--> $DIR/variance-trait-object-bound.rs:14:1
|
LL | struct TOption<'a> {

View file

@ -7,7 +7,7 @@
// not considered bivariant.
#[rustc_variance]
struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o]
struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [+, o, o]
t: &'a mut (A,B)
}

View file

@ -1,4 +1,4 @@
error: [-, o, o]
error: [+, o, o]
--> $DIR/variance-types.rs:10:1
|
LL | struct InvariantMut<'a,A:'a,B:'a> {