mirror of
https://github.com/rust-lang/rust
synced 2024-09-15 22:50:55 +00:00
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
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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>>>,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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 ()"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: [-, o]
|
||||
error: [+, o]
|
||||
--> $DIR/E0208.rs:4:1
|
||||
|
|
||||
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 @@ fn method(&'a self) { }
|
|||
}
|
||||
|
||||
#[rustc_variance]
|
||||
struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
|
||||
struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +]
|
||||
field: (T, &'a ())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: [-, +]
|
||||
error: [+, +]
|
||||
--> $DIR/variance-associated-types.rs:13:1
|
||||
|
|
||||
LL | struct Foo<'a, T : Trait<'a>> {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: [-]
|
||||
error: [+]
|
||||
--> $DIR/variance-trait-object-bound.rs:14:1
|
||||
|
|
||||
LL | struct TOption<'a> {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: [-, o, o]
|
||||
error: [+, o, o]
|
||||
--> $DIR/variance-types.rs:10:1
|
||||
|
|
||||
LL | struct InvariantMut<'a,A:'a,B:'a> {
|
||||
|
|
Loading…
Reference in a new issue