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:
commit
226b2496fc
39 changed files with 531 additions and 160 deletions
|
@ -1499,6 +1499,11 @@ pub fn create_vtable_di_node<'ll, 'tcx>(
|
||||||
return;
|
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 =
|
let vtable_name =
|
||||||
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
|
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);
|
let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref);
|
||||||
|
|
|
@ -27,7 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||||
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
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::middle::stability::AllowUnstable;
|
||||||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
|
@ -37,7 +37,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::lev_distance::find_best_match_for_name;
|
use rustc_span::lev_distance::find_best_match_for_name;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
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_target::spec::abi;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
||||||
|
@ -54,7 +54,7 @@ use std::slice;
|
||||||
pub struct PathSeg(pub DefId, pub usize);
|
pub struct PathSeg(pub DefId, pub usize);
|
||||||
|
|
||||||
pub trait AstConv<'tcx> {
|
pub trait AstConv<'tcx> {
|
||||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
|
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||||
|
|
||||||
fn item_def_id(&self) -> DefId;
|
fn item_def_id(&self) -> DefId;
|
||||||
|
|
||||||
|
@ -131,6 +131,8 @@ pub trait AstConv<'tcx> {
|
||||||
{
|
{
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -2132,48 +2134,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
)
|
)
|
||||||
.emit() // Already reported in an earlier stage.
|
.emit() // Already reported in an earlier stage.
|
||||||
} else {
|
} else {
|
||||||
// Find all the `impl`s that `qself_ty` has for any trait that has the
|
let traits: Vec<_> =
|
||||||
// associated type, so that we suggest the right one.
|
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
|
||||||
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();
|
|
||||||
|
|
||||||
// Don't print `TyErr` to the user.
|
// Don't print `TyErr` to the user.
|
||||||
self.report_ambiguous_associated_type(
|
self.report_ambiguous_associated_type(
|
||||||
|
@ -2232,6 +2194,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
Ok((ty, DefKind::AssocTy, assoc_ty_did))
|
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(
|
fn lookup_assoc_ty(
|
||||||
&self,
|
&self,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
|
|
|
@ -25,7 +25,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{GenericParamKind, Node};
|
use rustc_hir::{GenericParamKind, Node};
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
|
@ -517,6 +517,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
|
||||||
fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
|
fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
|
||||||
// There's no place to record types from signatures?
|
// 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.
|
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
|
||||||
|
|
|
@ -225,8 +225,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Ref(region, ty, mutbl) => {
|
ty::Ref(region, ty, mutbl) => {
|
||||||
let contra = self.contravariant(variance);
|
self.add_constraints_from_region(current, region, variance);
|
||||||
self.add_constraints_from_region(current, region, contra);
|
|
||||||
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
|
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,9 +257,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Dynamic(data, r, _) => {
|
ty::Dynamic(data, r, _) => {
|
||||||
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
|
// The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
|
||||||
let contra = self.contravariant(variance);
|
self.add_constraints_from_region(current, r, variance);
|
||||||
self.add_constraints_from_region(current, r, contra);
|
|
||||||
|
|
||||||
if let Some(poly_trait_ref) = data.principal() {
|
if let Some(poly_trait_ref) = data.principal() {
|
||||||
self.add_constraints_from_invariant_substs(
|
self.add_constraints_from_invariant_substs(
|
||||||
|
|
|
@ -324,6 +324,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||||
let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
|
let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
|
||||||
self.write_ty(hir_id, 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).
|
/// Represents a user-provided type in the raw form (never normalized).
|
||||||
|
|
|
@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||||
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
||||||
|
|
||||||
let origin = Subtype(Box::new(self.fields.trace.clone()));
|
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(),
|
self.tcx(),
|
||||||
origin,
|
origin,
|
||||||
a,
|
a,
|
||||||
|
|
|
@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||||
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
||||||
|
|
||||||
let origin = Subtype(Box::new(self.fields.trace.clone()));
|
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(),
|
self.tcx(),
|
||||||
origin,
|
origin,
|
||||||
a,
|
a,
|
||||||
|
|
|
@ -663,13 +663,13 @@ where
|
||||||
debug!(?v_b);
|
debug!(?v_b);
|
||||||
|
|
||||||
if self.ambient_covariance() {
|
if self.ambient_covariance() {
|
||||||
// Covariance: a <= b. Hence, `b: a`.
|
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
|
||||||
self.push_outlives(v_b, v_a, self.ambient_variance_info);
|
self.push_outlives(v_a, v_b, self.ambient_variance_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ambient_contravariance() {
|
if self.ambient_contravariance() {
|
||||||
// Contravariant: b <= a. Hence, `a: b`.
|
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
|
||||||
self.push_outlives(v_a, v_b, self.ambient_variance_info);
|
self.push_outlives(v_b, v_a, self.ambient_variance_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(a)
|
Ok(a)
|
||||||
|
|
|
@ -191,12 +191,13 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
||||||
// from the "cause" field, we could perhaps give more tailored
|
// from the "cause" field, we could perhaps give more tailored
|
||||||
// error messages.
|
// error messages.
|
||||||
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
|
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
|
||||||
|
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
|
||||||
self.fields
|
self.fields
|
||||||
.infcx
|
.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.unwrap_region_constraints()
|
.unwrap_region_constraints()
|
||||||
.make_subregion(origin, a, b);
|
.make_subregion(origin, b, a);
|
||||||
|
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,12 +443,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||||
if a_repr == b_repr =>
|
if a_repr == b_repr =>
|
||||||
{
|
{
|
||||||
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
|
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
|
||||||
relation.relate_with_variance(
|
relation.relate(a_region, b_region)
|
||||||
ty::Contravariant,
|
|
||||||
ty::VarianceDiagInfo::default(),
|
|
||||||
a_region,
|
|
||||||
b_region,
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr))
|
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)) => {
|
(&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
|
||||||
let r = relation.relate_with_variance(
|
let r = relation.relate(a_r, b_r)?;
|
||||||
ty::Contravariant,
|
|
||||||
ty::VarianceDiagInfo::default(),
|
|
||||||
a_r,
|
|
||||||
b_r,
|
|
||||||
)?;
|
|
||||||
let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
|
let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
|
||||||
let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
|
let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
|
||||||
let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
|
let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
|
||||||
|
|
|
@ -2353,6 +2353,28 @@ impl<'a> Parser<'a> {
|
||||||
Err(err)
|
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
|
/// Creates a dummy const argument, and reports that the expression must be enclosed in braces
|
||||||
pub fn dummy_const_arg_needs_braces(
|
pub fn dummy_const_arg_needs_braces(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -675,22 +675,42 @@ impl<'a> Parser<'a> {
|
||||||
GenericArg::Const(self.parse_const_arg()?)
|
GenericArg::Const(self.parse_const_arg()?)
|
||||||
} else if self.check_type() {
|
} else if self.check_type() {
|
||||||
// Parse type argument.
|
// Parse type argument.
|
||||||
let is_const_fn =
|
|
||||||
self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis));
|
// Proactively create a parser snapshot enabling us to rewind and try to reparse the
|
||||||
let mut snapshot = self.create_snapshot_for_diagnostic();
|
// 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() {
|
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) => {
|
Err(err) => {
|
||||||
if is_const_fn {
|
if let Some(snapshot) = snapshot
|
||||||
match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) {
|
&& let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
|
||||||
Ok(expr) => {
|
{
|
||||||
self.restore_snapshot(snapshot);
|
return Ok(Some(self.dummy_const_arg_needs_braces(
|
||||||
return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
|
err,
|
||||||
}
|
expr.span,
|
||||||
Err(err) => {
|
)));
|
||||||
err.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Try to recover from possible `const` arg without braces.
|
// Try to recover from possible `const` arg without braces.
|
||||||
return self.recover_const_arg(start, err).map(Some);
|
return self.recover_const_arg(start, err).map(Some);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Code shared by trait and projection goals for candidate assembly.
|
//! Code shared by trait and projection goals for candidate assembly.
|
||||||
|
|
||||||
use super::infcx_ext::InferCtxtExt;
|
use super::infcx_ext::InferCtxtExt;
|
||||||
|
#[cfg(doc)]
|
||||||
|
use super::trait_goals::structural_traits::*;
|
||||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
@ -98,52 +100,75 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
||||||
assumption: ty::Predicate<'tcx>,
|
assumption: ty::Predicate<'tcx>,
|
||||||
) -> QueryResult<'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(
|
fn consider_auto_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
|
// A trait alias holds if the RHS traits and `where` clauses hold.
|
||||||
fn consider_trait_alias_candidate(
|
fn consider_trait_alias_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> 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(
|
fn consider_builtin_sized_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> 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(
|
fn consider_builtin_copy_clone_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> 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(
|
fn consider_builtin_pointer_sized_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> 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(
|
fn consider_builtin_fn_trait_candidates(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
kind: ty::ClosureKind,
|
kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx>;
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
|
// `Tuple` is implemented if the `Self` type is a tuple.
|
||||||
fn consider_builtin_tuple_candidate(
|
fn consider_builtin_tuple_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> 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(
|
fn consider_builtin_pointee_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> 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(
|
fn consider_builtin_future_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> 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(
|
fn consider_builtin_generator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
|
|
|
@ -335,15 +335,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
// That won't actually reflect in the query response, so it seems moot.
|
// That won't actually reflect in the query response, so it seems moot.
|
||||||
self.make_canonical_response(Certainty::AMBIGUOUS)
|
self.make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
} else {
|
} else {
|
||||||
self.infcx.probe(|_| {
|
let InferOk { value: (), obligations } = self
|
||||||
let InferOk { value: (), obligations } = self
|
.infcx
|
||||||
.infcx
|
.at(&ObligationCause::dummy(), goal.param_env)
|
||||||
.at(&ObligationCause::dummy(), goal.param_env)
|
.sub(goal.predicate.a, goal.predicate.b)?;
|
||||||
.sub(goal.predicate.a, goal.predicate.b)?;
|
self.evaluate_all_and_make_canonical_response(
|
||||||
self.evaluate_all_and_make_canonical_response(
|
obligations.into_iter().map(|pred| pred.into()).collect(),
|
||||||
obligations.into_iter().map(|pred| pred.into()).collect(),
|
)
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,22 +374,22 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
|
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
self.infcx.probe(|_| {
|
match crate::traits::wf::unnormalized_obligations(
|
||||||
match crate::traits::wf::unnormalized_obligations(
|
self.infcx,
|
||||||
self.infcx,
|
goal.param_env,
|
||||||
goal.param_env,
|
goal.predicate,
|
||||||
goal.predicate,
|
) {
|
||||||
) {
|
Some(obligations) => self.evaluate_all_and_make_canonical_response(
|
||||||
Some(obligations) => self.evaluate_all_and_make_canonical_response(
|
obligations.into_iter().map(|o| o.into()).collect(),
|
||||||
obligations.into_iter().map(|o| o.into()).collect(),
|
),
|
||||||
),
|
None => self.make_canonical_response(Certainty::AMBIGUOUS),
|
||||||
None => self.make_canonical_response(Certainty::AMBIGUOUS),
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
// Recursively evaluates a list of goals to completion, returning the certainty
|
||||||
|
// of all of the goals.
|
||||||
fn evaluate_all(
|
fn evaluate_all(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||||
|
@ -428,6 +426,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(
|
fn evaluate_all_and_make_canonical_response(
|
||||||
&mut self,
|
&mut self,
|
||||||
goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||||
|
|
|
@ -296,7 +296,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Predicate<'tcx>,
|
assumption: ty::Predicate<'tcx>,
|
||||||
) -> QueryResult<'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(|_| {
|
ecx.infcx.probe(|_| {
|
||||||
let assumption_projection_pred =
|
let assumption_projection_pred =
|
||||||
ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
|
ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
|
||||||
|
|
|
@ -65,7 +65,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Predicate<'tcx>,
|
assumption: ty::Predicate<'tcx>,
|
||||||
) -> QueryResult<'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
|
// FIXME: Constness and polarity
|
||||||
ecx.infcx.probe(|_| {
|
ecx.infcx.probe(|_| {
|
||||||
let assumption_trait_pred =
|
let assumption_trait_pred =
|
||||||
|
|
|
@ -3807,13 +3807,13 @@ fn hint_missing_borrow<'tcx>(
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
) {
|
) {
|
||||||
let found_args = match found.kind() {
|
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 => {
|
kind => {
|
||||||
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
|
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let expected_args = match expected.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 => {
|
kind => {
|
||||||
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", 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);
|
let args = fn_decl.inputs.iter().map(|ty| ty);
|
||||||
|
|
||||||
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
|
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
|
||||||
let mut refs = 0;
|
let mut refs = vec![];
|
||||||
|
|
||||||
while let ty::Ref(_, new_ty, _) = ty.kind() {
|
while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
|
||||||
ty = *new_ty;
|
ty = *new_ty;
|
||||||
refs += 1;
|
refs.push(*mutbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
(ty, refs)
|
(ty, refs)
|
||||||
|
@ -3843,11 +3843,21 @@ fn hint_missing_borrow<'tcx>(
|
||||||
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
|
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 infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
|
||||||
if found_refs < expected_refs {
|
// FIXME: This could handle more exotic cases like mutability mismatches too!
|
||||||
to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
|
if found_refs.len() < expected_refs.len()
|
||||||
} else if found_refs > expected_refs {
|
&& 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 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;
|
let mut ty = arg;
|
||||||
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
|
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
|
||||||
span = span.with_hi(mut_ty.ty.span.lo());
|
span = span.with_hi(mut_ty.ty.span.lo());
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
use rustc_session::config::TraitSolver;
|
||||||
|
|
||||||
use crate::infer::canonical::OriginalQueryValues;
|
use crate::infer::canonical::OriginalQueryValues;
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
|
use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause};
|
||||||
use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
|
use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
|
||||||
|
|
||||||
pub trait InferCtxtExt<'tcx> {
|
pub trait InferCtxtExt<'tcx> {
|
||||||
|
@ -77,12 +79,38 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||||
_ => obligation.param_env.without_const(),
|
_ => obligation.param_env.without_const(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let c_pred = self
|
if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
|
||||||
.canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
|
let c_pred = self.canonicalize_query_keep_static(
|
||||||
// Run canonical query. If overflow occurs, rerun from scratch but this time
|
param_env.and(obligation.predicate),
|
||||||
// in standard trait query mode so that overflow is handled appropriately
|
&mut _orig_values,
|
||||||
// within `SelectionContext`.
|
);
|
||||||
self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
|
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
|
// Helper function that canonicalizes and runs the query. If an
|
||||||
|
@ -92,6 +120,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
) -> EvaluationResult {
|
) -> 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) {
|
match self.evaluate_obligation(obligation) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(OverflowError::Canonical) => {
|
Err(OverflowError::Canonical) => {
|
||||||
|
|
|
@ -551,7 +551,7 @@ use crate::marker::Destruct;
|
||||||
use crate::panicking::{panic, panic_str};
|
use crate::panicking::{panic, panic_str};
|
||||||
use crate::pin::Pin;
|
use crate::pin::Pin;
|
||||||
use crate::{
|
use crate::{
|
||||||
convert, hint, mem,
|
cmp, convert, hint, mem,
|
||||||
ops::{self, ControlFlow, Deref, DerefMut},
|
ops::{self, ControlFlow, Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2090,6 +2090,12 @@ impl<T: PartialEq> PartialEq for Option<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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")]
|
#[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait SpecOptionPartialEq: Sized {
|
pub trait SpecOptionPartialEq: Sized {
|
||||||
|
@ -2146,6 +2152,14 @@ impl<T> SpecOptionPartialEq for crate::ptr::NonNull<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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
|
// The Option Iterators
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -9,6 +9,14 @@
|
||||||
// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
|
// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
|
||||||
// ignore-tidy-linelength
|
// 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"
|
// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize"
|
||||||
// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, 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 ()"
|
// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
use core::cmp::Ordering;
|
||||||
use core::num::{NonZeroU32, NonZeroI64};
|
use core::num::{NonZeroU32, NonZeroI64};
|
||||||
use core::ptr::NonNull;
|
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
|
// CHECK-NEXT: ret i1
|
||||||
l == r
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -13,10 +13,34 @@ fn main() {
|
||||||
let _: Wow<A.0>;
|
let _: Wow<A.0>;
|
||||||
//~^ ERROR expected one of
|
//~^ ERROR expected one of
|
||||||
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
|
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
|
||||||
|
let _: Wow<[]>;
|
||||||
// FIXME(compiler-errors): This one is still unsatisfying,
|
//~^ ERROR expected type
|
||||||
// and probably a case I could see someone typing by accident..
|
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
|
||||||
let _: Wow<[12]>;
|
let _: Wow<[12]>;
|
||||||
//~^ ERROR expected type, found
|
//~^ ERROR expected type
|
||||||
//~| ERROR type provided when a constant was expected
|
//~| 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,18 +42,118 @@ help: expressions must be enclosed in braces to be used as const generic argumen
|
||||||
LL | let _: Wow<{ A.0 }>;
|
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`
|
error: expected type, found `12`
|
||||||
--> $DIR/bad-const-generic-exprs.rs:19:17
|
--> $DIR/bad-const-generic-exprs.rs:19:17
|
||||||
|
|
|
|
||||||
LL | let _: Wow<[12]>;
|
LL | let _: Wow<[12]>;
|
||||||
| ^^ expected type
|
| ^^ expected type
|
||||||
|
|
||||||
error[E0747]: type provided when a constant was expected
|
error: invalid const generic expression
|
||||||
--> $DIR/bad-const-generic-exprs.rs:19:16
|
--> $DIR/bad-const-generic-exprs.rs:19:16
|
||||||
|
|
|
|
||||||
LL | let _: Wow<[12]>;
|
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`.
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Foo<'a, T> { //~ ERROR [-, o]
|
struct Foo<'a, T> { //~ ERROR [+, o]
|
||||||
t: &'a mut T,
|
t: &'a mut T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: [-, o]
|
error: [+, o]
|
||||||
--> $DIR/E0208.rs:4:1
|
--> $DIR/E0208.rs:4:1
|
||||||
|
|
|
|
||||||
LL | struct Foo<'a, T> {
|
LL | struct Foo<'a, T> {
|
||||||
|
|
28
tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs
Normal file
28
tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs
Normal 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
|
||||||
|
}
|
|
@ -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`.
|
18
tests/ui/typeck/issue-107087.rs
Normal file
18
tests/ui/typeck/issue-107087.rs
Normal 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
|
||||||
|
}
|
9
tests/ui/typeck/issue-107087.stderr
Normal file
9
tests/ui/typeck/issue-107087.stderr
Normal 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`.
|
|
@ -10,7 +10,7 @@ trait Trait<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
|
struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +]
|
||||||
field: (T, &'a ())
|
field: (T, &'a ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: [-, +]
|
error: [+, +]
|
||||||
--> $DIR/variance-associated-types.rs:13:1
|
--> $DIR/variance-associated-types.rs:13:1
|
||||||
|
|
|
|
||||||
LL | struct Foo<'a, T : Trait<'a>> {
|
LL | struct Foo<'a, T : Trait<'a>> {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// Regions that just appear in normal spots are contravariant:
|
// Regions that just appear in normal spots are contravariant:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
|
struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +]
|
||||||
x: &'a isize,
|
x: &'a isize,
|
||||||
y: &'b [isize],
|
y: &'b [isize],
|
||||||
c: &'c str
|
c: &'c str
|
||||||
|
@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
|
||||||
// Those same annotations in function arguments become covariant:
|
// Those same annotations in function arguments become covariant:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
|
struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -]
|
||||||
x: extern "Rust" fn(&'a isize),
|
x: extern "Rust" fn(&'a isize),
|
||||||
y: extern "Rust" fn(&'b [isize]),
|
y: extern "Rust" fn(&'b [isize]),
|
||||||
c: extern "Rust" fn(&'c str),
|
c: extern "Rust" fn(&'c str),
|
||||||
|
@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
|
||||||
// Mutability induces invariance:
|
// Mutability induces invariance:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
|
struct Test4<'a, 'b:'a> { //~ ERROR [+, o]
|
||||||
x: &'a mut &'b isize,
|
x: &'a mut &'b isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
|
||||||
// contravariant context:
|
// contravariant context:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
|
struct Test5<'a, 'b:'a> { //~ ERROR [-, o]
|
||||||
x: extern "Rust" fn(&'a mut &'b isize),
|
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.
|
// argument list occurs in an invariant context.
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
|
struct Test6<'a, 'b:'a> { //~ ERROR [+, o]
|
||||||
x: &'a mut extern "Rust" fn(&'b isize),
|
x: &'a mut extern "Rust" fn(&'b isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ struct Test7<'a> { //~ ERROR [*]
|
||||||
// Try enums too.
|
// Try enums too.
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
|
enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
|
||||||
Test8A(extern "Rust" fn(&'a isize)),
|
Test8A(extern "Rust" fn(&'a isize)),
|
||||||
Test8B(&'b [isize]),
|
Test8B(&'b [isize]),
|
||||||
Test8C(&'b mut &'c str),
|
Test8C(&'b mut &'c str),
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
error: [-, -, -]
|
error: [+, +, +]
|
||||||
--> $DIR/variance-regions-direct.rs:9:1
|
--> $DIR/variance-regions-direct.rs:9:1
|
||||||
|
|
|
|
||||||
LL | struct Test2<'a, 'b, 'c> {
|
LL | struct Test2<'a, 'b, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, +, +]
|
error: [-, -, -]
|
||||||
--> $DIR/variance-regions-direct.rs:18:1
|
--> $DIR/variance-regions-direct.rs:18:1
|
||||||
|
|
|
|
||||||
LL | struct Test3<'a, 'b, 'c> {
|
LL | struct Test3<'a, 'b, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [-, o]
|
error: [+, o]
|
||||||
--> $DIR/variance-regions-direct.rs:27:1
|
--> $DIR/variance-regions-direct.rs:27:1
|
||||||
|
|
|
|
||||||
LL | struct Test4<'a, 'b:'a> {
|
LL | struct Test4<'a, 'b:'a> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, o]
|
error: [-, o]
|
||||||
--> $DIR/variance-regions-direct.rs:35:1
|
--> $DIR/variance-regions-direct.rs:35:1
|
||||||
|
|
|
|
||||||
LL | struct Test5<'a, 'b:'a> {
|
LL | struct Test5<'a, 'b:'a> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [-, o]
|
error: [+, o]
|
||||||
--> $DIR/variance-regions-direct.rs:45:1
|
--> $DIR/variance-regions-direct.rs:45:1
|
||||||
|
|
|
|
||||||
LL | struct Test6<'a, 'b:'a> {
|
LL | struct Test6<'a, 'b:'a> {
|
||||||
|
@ -34,7 +34,7 @@ error: [*]
|
||||||
LL | struct Test7<'a> {
|
LL | struct Test7<'a> {
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, -, o]
|
error: [-, +, o]
|
||||||
--> $DIR/variance-regions-direct.rs:59:1
|
--> $DIR/variance-regions-direct.rs:59:1
|
||||||
|
|
|
|
||||||
LL | enum Test8<'a, 'b, 'c:'b> {
|
LL | enum Test8<'a, 'b, 'c:'b> {
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_variance]
|
#[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)),
|
Test8A(extern "Rust" fn(&'a isize)),
|
||||||
Test8B(&'b [isize]),
|
Test8B(&'b [isize]),
|
||||||
Test8C(&'b mut &'c str),
|
Test8C(&'b mut &'c str),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
#[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>
|
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)
|
#[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>
|
f: Base<'a, 'b, 'a, 'c>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
|
#[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>
|
f: Base<'a, 'b, 'c, 'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
error: [+, -, o, *]
|
error: [-, +, o, *]
|
||||||
--> $DIR/variance-regions-indirect.rs:8:1
|
--> $DIR/variance-regions-indirect.rs:8:1
|
||||||
|
|
|
|
||||||
LL | enum Base<'a, 'b, 'c:'b, 'd> {
|
LL | enum Base<'a, 'b, 'c:'b, 'd> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [*, o, -, +]
|
error: [*, o, +, -]
|
||||||
--> $DIR/variance-regions-indirect.rs:15:1
|
--> $DIR/variance-regions-indirect.rs:15:1
|
||||||
|
|
|
|
||||||
LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
|
LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
|
||||||
|
@ -16,13 +16,13 @@ error: [o, o, *]
|
||||||
LL | struct Derived2<'a, 'b:'a, 'c> {
|
LL | struct Derived2<'a, 'b:'a, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [o, -, *]
|
error: [o, +, *]
|
||||||
--> $DIR/variance-regions-indirect.rs:25:1
|
--> $DIR/variance-regions-indirect.rs:25:1
|
||||||
|
|
|
|
||||||
LL | struct Derived3<'a:'b, 'b, 'c> {
|
LL | struct Derived3<'a:'b, 'b, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, -, o]
|
error: [-, +, o]
|
||||||
--> $DIR/variance-regions-indirect.rs:30:1
|
--> $DIR/variance-regions-indirect.rs:30:1
|
||||||
|
|
|
|
||||||
LL | struct Derived4<'a, 'b, 'c:'b> {
|
LL | struct Derived4<'a, 'b, 'c:'b> {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::mem;
|
||||||
trait T { fn foo(&self); }
|
trait T { fn foo(&self); }
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct TOption<'a> { //~ ERROR [-]
|
struct TOption<'a> { //~ ERROR [+]
|
||||||
v: Option<Box<dyn T + 'a>>,
|
v: Option<Box<dyn T + 'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: [-]
|
error: [+]
|
||||||
--> $DIR/variance-trait-object-bound.rs:14:1
|
--> $DIR/variance-trait-object-bound.rs:14:1
|
||||||
|
|
|
|
||||||
LL | struct TOption<'a> {
|
LL | struct TOption<'a> {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::cell::Cell;
|
||||||
// not considered bivariant.
|
// not considered bivariant.
|
||||||
|
|
||||||
#[rustc_variance]
|
#[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)
|
t: &'a mut (A,B)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: [-, o, o]
|
error: [+, o, o]
|
||||||
--> $DIR/variance-types.rs:10:1
|
--> $DIR/variance-types.rs:10:1
|
||||||
|
|
|
|
||||||
LL | struct InvariantMut<'a,A:'a,B:'a> {
|
LL | struct InvariantMut<'a,A:'a,B:'a> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue