Auto merge of #108998 - matthiaskrgr:rollup-sxbdulg, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - #106921 (Add documentation about the memory layout of `Cell`)
 - #108828 (Emit alias-eq when equating numeric var and projection)
 - #108834 (Do not ICE when we have fn pointer `Fn` obligations with bound vars in the self type)
 - #108900 (fix(lexer): print whitespace warning for \x0c)
 - #108930 (feat: implement better error for manual impl of `Fn*` traits)
 - #108937 (improve readability of winnowing)
 - #108947 (Don't even try to combine consts with incompatible types)
 - #108976 (Update triagebot rust-analyzer team mention)
 - #108983 (Forbid `#[target_feature]` on safe default implementations)

Failed merges:

 - #108950 (Directly construct Inherited in typeck.)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-11 04:17:59 +00:00
commit 19c53768af
45 changed files with 535 additions and 182 deletions

View File

@ -442,7 +442,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
if let DefKind::AssocFn = tcx.def_kind(id) {
let parent_id = tcx.local_parent(id);
if let DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
tcx.sess
.struct_span_err(
attr_span,

View File

@ -42,6 +42,9 @@ hir_analysis_assoc_type_binding_not_allowed =
associated type bindings are not allowed here
.label = associated type not allowed here
hir_analysis_parenthesized_fn_trait_expansion =
parenthesized trait syntax expands to `{$expanded_type}`
hir_analysis_typeof_reserved_keyword_used =
`typeof` is a reserved keyword but unimplemented
.suggestion = consider replacing `typeof(...)` with an actual type

View File

@ -1,10 +1,14 @@
use crate::astconv::AstConv;
use crate::errors::{ManualImplementation, MissingTypeParams};
use crate::errors::{
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::FulfillmentError;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
@ -78,43 +82,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Do not suggest the other syntax if we are in trait impl:
// the desugaring would contain an associated type constraint.
if !is_impl {
let args = trait_segment
.args
.as_ref()
.and_then(|args| args.args.get(0))
.and_then(|arg| match arg {
hir::GenericArg::Type(ty) => match ty.kind {
hir::TyKind::Tup(t) => t
.iter()
.map(|e| sess.source_map().span_to_snippet(e.span))
.collect::<Result<Vec<_>, _>>()
.map(|a| a.join(", ")),
_ => sess.source_map().span_to_snippet(ty.span),
}
.map(|s| format!("({})", s))
.ok(),
_ => None,
})
.unwrap_or_else(|| "()".to_string());
let ret = trait_segment
.args()
.bindings
.iter()
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
(true, hir::TypeBindingKind::Equality { term }) => {
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
};
sess.source_map().span_to_snippet(span).ok()
}
_ => None,
})
.unwrap_or_else(|| "()".to_string());
err.span_suggestion(
span,
"use parenthetical notation instead",
format!("{}{} -> {}", trait_segment.ident, args, ret),
fn_trait_to_string(self.tcx(), trait_segment, true),
Applicability::MaybeIncorrect,
);
}
@ -629,3 +600,69 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.emit();
}
}
/// Emits an error regarding forbidden type binding associations
pub fn prohibit_assoc_ty_binding(
tcx: TyCtxt<'_>,
span: Span,
segment: Option<(&hir::PathSegment<'_>, Span)>,
) {
tcx.sess.emit_err(AssocTypeBindingNotAllowed { span, fn_trait_expansion: if let Some((segment, span)) = segment && segment.args().parenthesized {
Some(ParenthesizedFnTraitExpansion { span, expanded_type: fn_trait_to_string(tcx, segment, false) })
} else {
None
}});
}
pub(crate) fn fn_trait_to_string(
tcx: TyCtxt<'_>,
trait_segment: &hir::PathSegment<'_>,
parenthesized: bool,
) -> String {
let args = trait_segment
.args
.as_ref()
.and_then(|args| args.args.get(0))
.and_then(|arg| match arg {
hir::GenericArg::Type(ty) => match ty.kind {
hir::TyKind::Tup(t) => t
.iter()
.map(|e| tcx.sess.source_map().span_to_snippet(e.span))
.collect::<Result<Vec<_>, _>>()
.map(|a| a.join(", ")),
_ => tcx.sess.source_map().span_to_snippet(ty.span),
}
.map(|s| {
// `s.empty()` checks to see if the type is the unit tuple, if so we don't want a comma
if parenthesized || s.is_empty() { format!("({})", s) } else { format!("({},)", s) }
})
.ok(),
_ => None,
})
.unwrap_or_else(|| "()".to_string());
let ret = trait_segment
.args()
.bindings
.iter()
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
(true, hir::TypeBindingKind::Equality { term }) => {
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(c) => tcx.hir().span(c.hir_id),
};
(span != tcx.hir().span(trait_segment.hir_id))
.then_some(tcx.sess.source_map().span_to_snippet(span).ok())
.flatten()
}
_ => None,
})
.unwrap_or_else(|| "()".to_string());
if parenthesized {
format!("{}{} -> {}", trait_segment.ident, args, ret)
} else {
format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
}
}

View File

@ -1,9 +1,8 @@
use super::IsMethodCall;
use crate::astconv::{
CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, GenericArgPosition,
errors::prohibit_assoc_ty_binding, CreateSubstsForGenericArgsCtxt, ExplicitLateBound,
GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
};
use crate::errors::AssocTypeBindingNotAllowed;
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@ -433,7 +432,7 @@ pub(crate) fn check_generic_arg_count(
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
prohibit_assoc_ty_binding(tcx, b.span);
prohibit_assoc_ty_binding(tcx, b.span, None);
}
let explicit_late_bound =
@ -589,11 +588,6 @@ pub(crate) fn check_generic_arg_count(
}
}
/// Emits an error regarding forbidden type binding associations
pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) {
tcx.sess.emit_err(AssocTypeBindingNotAllowed { span });
}
/// Prohibits explicit lifetime arguments if late-bound lifetime parameters
/// are present. This is used both for datatypes and function calls.
pub(crate) fn prohibit_explicit_late_bound_lifetimes(

View File

@ -5,9 +5,8 @@
mod errors;
pub mod generics;
use crate::astconv::generics::{
check_generic_arg_count, create_substs_for_generic_args, prohibit_assoc_ty_binding,
};
use crate::astconv::errors::prohibit_assoc_ty_binding;
use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args};
use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
use crate::errors::{
@ -295,7 +294,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span);
prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
}
substs
@ -631,7 +630,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span);
prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
}
args
@ -825,7 +824,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
constness,
);
if let Some(b) = trait_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span);
prohibit_assoc_ty_binding(self.tcx(), b.span, Some((trait_segment, span)));
}
self.tcx().mk_trait_ref(trait_def_id, substs)
}
@ -2596,7 +2595,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span);
prohibit_assoc_ty_binding(self.tcx(), b.span, None);
return true;
}
}

View File

@ -129,6 +129,18 @@ pub struct AssocTypeBindingNotAllowed {
#[primary_span]
#[label]
pub span: Span,
#[subdiagnostic]
pub fn_trait_expansion: Option<ParenthesizedFnTraitExpansion>,
}
#[derive(Subdiagnostic)]
#[help(hir_analysis_parenthesized_fn_trait_expansion)]
pub struct ParenthesizedFnTraitExpansion {
#[primary_span]
pub span: Span,
pub expanded_type: String,
}
#[derive(Diagnostic)]

View File

@ -148,13 +148,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rhs_ty,
op,
);
self.demand_suptype(expr.span, builtin_return_ty, return_ty);
}
self.demand_eqtype(expr.span, builtin_return_ty, return_ty);
builtin_return_ty
} else {
return_ty
}
}
}
}
fn enforce_builtin_binop_types(
&self,

View File

@ -411,15 +411,28 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
ty::Infer(ty::IntVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_int_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
t,
),
ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
)
}
}
ty::Infer(ty::FloatVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_float_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
t,
),
)
}
}
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")

View File

@ -34,7 +34,6 @@ use rustc_hir::def_id::DefId;
use rustc_middle::infer::canonical::OriginalQueryValues;
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@ -119,20 +118,30 @@ impl<'tcx> InferCtxt<'tcx> {
self.unify_float_variable(!a_is_expected, v_id, v)
}
// We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
(
ty::Alias(AliasKind::Projection, _),
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
)
| (
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
ty::Alias(AliasKind::Projection, _),
) if self.tcx.trait_solver_next() => {
bug!()
}
(_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
if self.tcx.trait_solver_next() =>
{
relation.register_type_equate_obligation(a, b);
Ok(a)
}
// All other cases of inference are errors
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
}
(ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => {
relation.register_type_equate_obligation(a, b);
Ok(b)
}
(_, ty::Alias(AliasKind::Projection, _)) if self.tcx.trait_solver_next() => {
relation.register_type_equate_obligation(b, a);
Ok(a)
}
_ => ty::relate::super_relate_tys(relation, a, b),
}
}
@ -161,9 +170,9 @@ impl<'tcx> InferCtxt<'tcx> {
//
// This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
// ourselves with a check to find bugs being required for code to compile because it made inference progress.
self.probe(|_| {
let compatible_types = self.probe(|_| {
if a.ty() == b.ty() {
return;
return Ok(());
}
// We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
@ -173,15 +182,24 @@ impl<'tcx> InferCtxt<'tcx> {
(relation.param_env(), a.ty(), b.ty()),
&mut OriginalQueryValues::default(),
);
if let Err(NoSolution) = self.tcx.check_tys_might_be_eq(canonical) {
self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
self.tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,),
);
}
)
})
});
// If the consts have differing types, just bail with a const error with
// the expected const's type. Specifically, we don't want const infer vars
// to do any type shapeshifting before and after resolution.
if let Err(guar) = compatible_types {
return Ok(self.tcx.const_error_with_guaranteed(
if relation.a_is_expected() { a.ty() } else { b.ty() },
guar,
));
}
match (a.kind(), b.kind()) {
(
ty::ConstKind::Infer(InferConst::Var(a_vid)),

View File

@ -1363,6 +1363,28 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().const_unification_table().find(var)
}
/// Resolves an int var to a rigid int type, if it was constrained to one,
/// or else the root int var in the unification table.
pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
let mut inner = self.inner.borrow_mut();
if let Some(value) = inner.int_unification_table().probe_value(vid) {
value.to_type(self.tcx)
} else {
self.tcx.mk_int_var(inner.int_unification_table().find(vid))
}
}
/// Resolves a float var to a rigid int type, if it was constrained to one,
/// or else the root float var in the unification table.
pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
let mut inner = self.inner.borrow_mut();
if let Some(value) = inner.float_unification_table().probe_value(vid) {
value.to_type(self.tcx)
} else {
self.tcx.mk_float_var(inner.float_unification_table().find(vid))
}
}
/// Where possible, replaces type/const variables in
/// `value` with their final value. Note that region variables
/// are unaffected. If a type/const variable has not been unified, it

View File

@ -298,10 +298,10 @@ where
}
let tail = &tail[first_non_space..];
if let Some(c) = tail.chars().nth(0) {
if c.is_whitespace() {
// For error reporting, we would like the span to contain the character that was not
// skipped. The +1 is necessary to account for the leading \ that started the escape.
let end = start + first_non_space + c.len_utf8() + 1;
if c.is_whitespace() {
callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
}
}

View File

@ -135,6 +135,9 @@ impl<'tcx> Const<'tcx> {
_,
&hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. },
)) => {
// Use the type from the param's definition, since we can resolve it,
// not the expected parameter type from WithOptConstParam.
let param_ty = tcx.type_of(def_id).subst_identity();
match tcx.named_bound_var(expr.hir_id) {
Some(rbv::ResolvedArg::EarlyBound(_)) => {
// Find the name and index of the const parameter by indexing the generics of
@ -143,14 +146,14 @@ impl<'tcx> Const<'tcx> {
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.item_name(def_id);
Some(tcx.mk_const(ty::ParamConst::new(index, name), ty))
Some(tcx.mk_const(ty::ParamConst::new(index, name), param_ty))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => Some(tcx.mk_const(
ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)),
ty,
param_ty,
)),
Some(rbv::ResolvedArg::Error(guar)) => {
Some(tcx.const_error_with_guaranteed(ty, guar))
Some(tcx.const_error_with_guaranteed(param_ty, guar))
}
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id),
}

View File

@ -995,7 +995,7 @@ impl<'tcx> Term<'tcx> {
pub fn is_infer(&self) -> bool {
match self.unpack() {
TermKind::Ty(ty) => ty.is_ty_or_numeric_infer(),
TermKind::Ty(ty) => ty.is_ty_var(),
TermKind::Const(ct) => ct.is_ct_infer(),
}
}

View File

@ -709,7 +709,7 @@ parse_zero_chars = empty character literal
parse_lone_slash = invalid trailing slash in literal
.label = {parse_lone_slash}
parse_unskipped_whitespace = non-ASCII whitespace symbol '{$ch}' is not skipped
parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
.label = {parse_unskipped_whitespace}
parse_multiple_skipped_lines = multiple lines skipped by escaped newline

View File

@ -278,16 +278,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
}
}
ty::Infer(ty::IntVar(_)) => {
let nt = self.infcx.shallow_resolve(t);
ty::Infer(ty::IntVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_int_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
}
}
ty::Infer(ty::FloatVar(_)) => {
let nt = self.infcx.shallow_resolve(t);
ty::Infer(ty::FloatVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_float_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {

View File

@ -601,10 +601,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, "confirm_fn_pointer_candidate");
let tcx = self.tcx();
let self_ty = self
let Some(self_ty) = self
.infcx
.shallow_resolve(obligation.self_ty().no_bound_vars())
.expect("fn pointer should not capture bound vars from predicate");
.shallow_resolve(obligation.self_ty().no_bound_vars()) else
{
// FIXME: Ideally we'd support `for<'a> fn(&'a ()): Fn(&'a ())`,
// but we do not currently. Luckily, such a bound is not
// particularly useful, so we don't expect users to write
// them often.
return Err(SelectionError::Unimplemented);
};
let sig = self_ty.fn_sig(tcx);
let trait_ref = closure_trait_ref_and_return_type(
tcx,

View File

@ -465,14 +465,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if candidates.len() > 1 {
let mut i = 0;
while i < candidates.len() {
let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
self.candidate_should_be_dropped_in_favor_of(
&candidates[i],
&candidates[j],
needs_infer,
)
) == DropVictim::Yes
});
if is_dup {
if should_drop_i {
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
candidates.swap_remove(i);
} else {
@ -1842,16 +1842,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ProjectionMatchesProjection::No
}
}
}
///////////////////////////////////////////////////////////////////////////
// WINNOW
//
// Winnowing is the process of attempting to resolve ambiguity by
// probing further. During the winnowing process, we unify all
// type variables and then we also attempt to evaluate recursive
// bounds to see if they are satisfied.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum DropVictim {
Yes,
No,
}
/// Returns `true` if `victim` should be dropped in favor of
/// ## Winnowing
///
/// Winnowing is the process of attempting to resolve ambiguity by
/// probing further. During the winnowing process, we unify all
/// type variables and then we also attempt to evaluate recursive
/// bounds to see if they are satisfied.
impl<'tcx> SelectionContext<'_, 'tcx> {
/// Returns `DropVictim::Yes` if `victim` should be dropped in favor of
/// `other`. Generally speaking we will drop duplicate
/// candidates and prefer where-clause candidates.
///
@ -1861,9 +1867,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
victim: &EvaluatedCandidate<'tcx>,
other: &EvaluatedCandidate<'tcx>,
needs_infer: bool,
) -> bool {
) -> DropVictim {
if victim.candidate == other.candidate {
return true;
return DropVictim::Yes;
}
// Check if a bound would previously have been removed when normalizing
@ -1887,11 +1893,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// FIXME(@jswrenn): this should probably be more sophisticated
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No,
// (*)
(BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => true,
(_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => false,
(BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => {
DropVictim::Yes
}
(_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => {
DropVictim::No
}
(ParamCandidate(other), ParamCandidate(victim)) => {
let same_except_bound_vars = other.skip_binder().trait_ref
@ -1905,28 +1915,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// or the current one if tied (they should both evaluate to the same answer). This is
// probably best characterized as a "hack", since we might prefer to just do our
// best to *not* create essentially duplicate candidates in the first place.
other.bound_vars().len() <= victim.bound_vars().len()
if other.bound_vars().len() <= victim.bound_vars().len() {
DropVictim::Yes
} else {
DropVictim::No
}
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
&& other.skip_binder().polarity == victim.skip_binder().polarity
{
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
DropVictim::Yes
} else {
false
DropVictim::No
}
}
// Drop otherwise equivalent non-const fn pointer candidates
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
// Global bounds from the where clause should be ignored
// here (see issue #50825). Otherwise, we have a where
// clause so don't go around looking for impls.
// Arbitrarily give param candidates priority
// over projection and object candidates.
(
ParamCandidate(ref cand),
ParamCandidate(ref other_cand),
ImplCandidate(..)
| ClosureCandidate { .. }
| GeneratorCandidate
@ -1939,11 +1948,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitAliasCandidate
| ObjectCandidate(_)
| ProjectionCandidate(..),
) => !is_global(cand),
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref cand)) => {
) => {
if is_global(other_cand) {
DropVictim::No
} else {
// We have a where clause so don't go around looking
// for impls. Arbitrarily give param candidates priority
// over projection and object candidates.
//
// Global bounds from the where clause should be ignored
// here (see issue #50825).
DropVictim::Yes
}
}
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(cand)
if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
}
(
ImplCandidate(_)
@ -1956,18 +1977,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate,
ParamCandidate(ref cand),
ParamCandidate(ref victim_cand),
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(cand) && other.evaluation.must_apply_modulo_regions()
if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() {
DropVictim::Yes
} else {
DropVictim::No
}
}
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
| (ObjectCandidate(i), ObjectCandidate(j)) => {
// Arbitrarily pick the lower numbered candidate for backwards
// compatibility reasons. Don't let this affect inference.
i < j && !needs_infer
if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No }
}
(ObjectCandidate(_), ProjectionCandidate(..))
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
@ -1987,7 +2012,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| TraitAliasCandidate,
) => true,
) => DropVictim::Yes,
(
ImplCandidate(..)
@ -2001,7 +2026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinCandidate { .. }
| TraitAliasCandidate,
ObjectCandidate(_) | ProjectionCandidate(..),
) => false,
) => DropVictim::No,
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
// See if we can toss out `victim` based on specialization.
@ -2014,7 +2039,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.tcx();
if other.evaluation.must_apply_modulo_regions() {
if tcx.specializes((other_def, victim_def)) {
return true;
return DropVictim::Yes;
}
}
@ -2060,13 +2085,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// will then correctly report an inference error, since the
// existence of multiple marker trait impls tells us nothing
// about which one should actually apply.
!needs_infer
if needs_infer { DropVictim::No } else { DropVictim::Yes }
}
Some(_) => true,
None => false,
Some(_) => DropVictim::Yes,
None => DropVictim::No,
}
} else {
false
DropVictim::No
}
}
@ -2092,10 +2117,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate,
) => false,
) => DropVictim::No,
}
}
}
impl<'tcx> SelectionContext<'_, 'tcx> {
fn sized_conditions(
&mut self,
obligation: &TraitObligation<'tcx>,

View File

@ -99,10 +99,10 @@ pub fn translate_substs<'tcx>(
}
fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
|_| {
|()| {
bug!(
"When translating substitutions for specialization, the expected \
specialization failed to hold"
"When translating substitutions from {source_impl:?} to {target_impl:?}, \
the expected specialization failed to hold"
)
},
)

View File

@ -209,6 +209,12 @@ pub use once::OnceCell;
/// A mutable memory location.
///
/// # Memory layout
///
/// `Cell<T>` has the same [memory layout and caveats as
/// `UnsafeCell<T>`](UnsafeCell#memory-layout). In particular, this means that
/// `Cell<T>` has the same in-memory representation as its inner type `T`.
///
/// # Examples
///
/// In this example, you can see that `Cell<T>` enables mutation inside an

View File

@ -1,5 +1,6 @@
fn foo<const N: usize>() -> [u8; N] {
bar::<N>() //~ ERROR mismatched types
//~^ ERROR the constant `N` is not of type `u8`
}
fn bar<const N: u8>() -> [u8; N] {}

View File

@ -1,3 +1,15 @@
error: the constant `N` is not of type `u8`
--> $DIR/type_mismatch.rs:2:5
|
LL | bar::<N>()
| ^^^^^^^^
|
note: required by a bound in `bar`
--> $DIR/type_mismatch.rs:6:8
|
LL | fn bar<const N: u8>() -> [u8; N] {}
| ^^^^^^^^^^^ required by this bound in `bar`
error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:2:11
|
@ -5,7 +17,7 @@ LL | bar::<N>()
| ^ expected `u8`, found `usize`
error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:5:26
--> $DIR/type_mismatch.rs:6:26
|
LL | fn bar<const N: u8>() -> [u8; N] {}
| --- ^^^^^^^ expected `[u8; N]`, found `()`
@ -13,11 +25,11 @@ LL | fn bar<const N: u8>() -> [u8; N] {}
| implicitly returns `()` as its body has no tail or `return` expression
error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:5:31
--> $DIR/type_mismatch.rs:6:31
|
LL | fn bar<const N: u8>() -> [u8; N] {}
| ^ expected `usize`, found `u8`
error: aborting due to 3 previous errors
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -6,6 +6,5 @@ impl X {
}
fn getn<const N: cfg_attr>() -> [u8; N] {}
//~^ ERROR expected type, found built-in attribute `cfg_attr`
//~| ERROR mismatched types
fn main() {}

View File

@ -10,15 +10,7 @@ error[E0573]: expected type, found built-in attribute `cfg_attr`
LL | fn getn<const N: cfg_attr>() -> [u8; N] {}
| ^^^^^^^^ not a type
error[E0308]: mismatched types
--> $DIR/type_not_in_scope.rs:7:33
|
LL | fn getn<const N: cfg_attr>() -> [u8; N] {}
| ---- ^^^^^^^ expected `[u8; N]`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0412, E0573.
For more information about an error, try `rustc --explain E0308`.
Some errors have detailed explanations: E0412, E0573.
For more information about an error, try `rustc --explain E0412`.

View File

@ -64,6 +64,12 @@ error[E0229]: associated type bindings are not allowed here
|
LL | impl FnOnce() for Foo1 {
| ^^^^^^^^ associated type not allowed here
|
help: parenthesized trait syntax expands to `FnOnce<(), Output=()>`
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6
|
LL | impl FnOnce() for Foo1 {
| ^^^^^^^^
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6

View File

@ -0,0 +1,13 @@
#![feature(fn_traits)]
#![feature(unboxed_closures)]
struct S;
impl Fn(u32) -> u32 for S {
//~^ ERROR associated type bindings are not allowed here [E0229]
fn call(&self) -> u32 {
5
}
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0229]: associated type bindings are not allowed here
--> $DIR/issue-39259.rs:6:17
|
LL | impl Fn(u32) -> u32 for S {
| ^^^ associated type not allowed here
|
help: parenthesized trait syntax expands to `Fn<(u32,), Output=u32>`
--> $DIR/issue-39259.rs:6:6
|
LL | impl Fn(u32) -> u32 for S {
| ^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0229`.

View File

@ -0,0 +1,19 @@
error[E0277]: expected a `Fn<(&'w (),)>` closure, found `fn(&'w ())`
--> $DIR/fn-ptr.rs:12:5
|
LL | ice();
| ^^^ expected an `Fn<(&'w (),)>` closure, found `fn(&'w ())`
|
= help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())`
note: required by a bound in `ice`
--> $DIR/fn-ptr.rs:7:25
|
LL | fn ice()
| --- required by a bound in this function
LL | where
LL | for<'w> fn(&'w ()): Fn(&'w ()),
| ^^^^^^^^^^ required by this bound in `ice`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,14 @@
// revisions: classic next
//[next] compile-flags: -Ztrait-solver=next
//[next] check-pass
fn ice()
where
for<'w> fn(&'w ()): Fn(&'w ()),
{
}
fn main() {
ice();
//[classic]~^ ERROR expected a `Fn<(&'w (),)>` closure, found `fn(&'w ())`
}

View File

@ -1,16 +1,19 @@
fn first() {
second == 1 //~ ERROR binary operation
//~^ ERROR mismatched types
//~| ERROR mismatched types
}
fn second() {
first == 1 //~ ERROR binary operation
//~^ ERROR mismatched types
//~| ERROR mismatched types
}
fn bar() {
bar == 1 //~ ERROR binary operation
//~^ ERROR mismatched types
//~| ERROR mismatched types
}
fn main() {}

View File

@ -15,8 +15,16 @@ LL | second == 1
= note: expected fn item `fn() {second}`
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:2:5
|
LL | fn first() {
| - help: try adding a return type: `-> bool`
LL | second == 1
| ^^^^^^^^^^^ expected `()`, found `bool`
error[E0369]: binary operation `==` cannot be applied to type `fn() {first}`
--> $DIR/issue-66667-function-cmp-cycle.rs:7:11
--> $DIR/issue-66667-function-cmp-cycle.rs:8:11
|
LL | first == 1
| ----- ^^ - {integer}
@ -24,7 +32,7 @@ LL | first == 1
| fn() {first}
error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:7:14
--> $DIR/issue-66667-function-cmp-cycle.rs:8:14
|
LL | first == 1
| ^ expected fn item, found integer
@ -32,8 +40,16 @@ LL | first == 1
= note: expected fn item `fn() {first}`
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:8:5
|
LL | fn second() {
| - help: try adding a return type: `-> bool`
LL | first == 1
| ^^^^^^^^^^ expected `()`, found `bool`
error[E0369]: binary operation `==` cannot be applied to type `fn() {bar}`
--> $DIR/issue-66667-function-cmp-cycle.rs:12:9
--> $DIR/issue-66667-function-cmp-cycle.rs:14:9
|
LL | bar == 1
| --- ^^ - {integer}
@ -41,7 +57,7 @@ LL | bar == 1
| fn() {bar}
error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:12:12
--> $DIR/issue-66667-function-cmp-cycle.rs:14:12
|
LL | bar == 1
| ^ expected fn item, found integer
@ -49,7 +65,15 @@ LL | bar == 1
= note: expected fn item `fn() {bar}`
found type `{integer}`
error: aborting due to 6 previous errors
error[E0308]: mismatched types
--> $DIR/issue-66667-function-cmp-cycle.rs:14:5
|
LL | fn bar() {
| - help: try adding a return type: `-> bool`
LL | bar == 1
| ^^^^^^^^ expected `()`, found `bool`
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

View File

@ -25,6 +25,12 @@ error[E0229]: associated type bindings are not allowed here
|
LL | impl Fn(&isize) for Error {
| ^^^^^^^^^^ associated type not allowed here
|
help: parenthesized trait syntax expands to `Fn<(&isize,), Output=()>`
--> $DIR/issue-95023.rs:3:6
|
LL | impl Fn(&isize) for Error {
| ^^^^^^^^^^
error[E0220]: associated type `B` not found for `Self`
--> $DIR/issue-95023.rs:6:44

View File

@ -18,4 +18,10 @@ impl Foo for Bar {
unsafe fn unsf_foo(&self) {}
}
trait Qux {
#[target_feature(enable = "sse2")]
//~^ ERROR cannot be applied to safe trait method
fn foo(&self) {}
}
fn main() {}

View File

@ -1,3 +1,12 @@
error: `#[target_feature(..)]` cannot be applied to safe trait method
--> $DIR/trait-impl.rs:22:5
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
LL |
LL | fn foo(&self) {}
| ------------- not an `unsafe` function
error: `#[target_feature(..)]` cannot be applied to safe trait method
--> $DIR/trait-impl.rs:13:5
|
@ -7,5 +16,5 @@ LL |
LL | fn foo(&self) {}
| ------------- not an `unsafe` function
error: aborting due to previous error
error: aborting due to 2 previous errors

View File

@ -0,0 +1,12 @@
#![feature(min_specialization)]
// An impl that has an erroneous const substitution should not specialize one
// that is well-formed.
struct S<const L: usize>;
impl<const N: i32> Copy for S<N> {}
impl<const M: usize> Copy for S<M> {}
//~^ ERROR conflicting implementations of trait `Copy` for type `S<_>`
fn main() {}

View File

@ -0,0 +1,11 @@
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
--> $DIR/bad-const-wf-doesnt-specialize.rs:9:1
|
LL | impl<const N: i32> Copy for S<N> {}
| -------------------------------- first implementation here
LL | impl<const M: usize> Copy for S<M> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -1,11 +1,31 @@
// check-pass
// ignore-tidy-tab
fn main() {
let s = "\
";
//~^^^ WARNING multiple lines skipped by escaped newline
assert_eq!(s, "");
let s = "foo\
  bar
";
//~^^^ WARNING non-ASCII whitespace symbol '\u{a0}' is not skipped
//~^^^ WARNING whitespace symbol '\u{a0}' is not skipped
assert_eq!(s, "foo  bar\n ");
let s = "a\
b";
assert_eq!(s, "ab");
let s = "a\
b";
assert_eq!(s, "ab");
let s = "a\
b";
//~^^ WARNING whitespace symbol '\u{c}' is not skipped
// '\x0c' is ASCII whitespace, but it may not need skipped
// discussion: https://github.com/rust-lang/rust/pull/108403
assert_eq!(s, "a\x0cb");
}

View File

@ -1,5 +1,5 @@
warning: multiple lines skipped by escaped newline
--> $DIR/str-escape.rs:3:14
--> $DIR/str-escape.rs:5:14
|
LL | let s = "\
| ______________^
@ -7,15 +7,25 @@ LL | |
LL | | ";
| |_____________^ skipping everything up to and including this point
warning: non-ASCII whitespace symbol '\u{a0}' is not skipped
--> $DIR/str-escape.rs:7:17
warning: whitespace symbol '\u{a0}' is not skipped
--> $DIR/str-escape.rs:11:17
|
LL | let s = "foo\
| _________________^
LL | |   bar
| | ^ non-ASCII whitespace symbol '\u{a0}' is not skipped
| | ^ whitespace symbol '\u{a0}' is not skipped
| |___|
|
warning: 2 warnings emitted
warning: whitespace symbol '\u{c}' is not skipped
--> $DIR/str-escape.rs:25:15
|
LL | let s = "a\
| _______________^
LL | | b";
| | ^- whitespace symbol '\u{c}' is not skipped
| |____|
|
warning: 3 warnings emitted

View File

@ -17,6 +17,12 @@ error[E0229]: associated type bindings are not allowed here
|
LL | impl Fn(&isize) for Error {
| ^^^^^^^^^^ associated type not allowed here
|
help: parenthesized trait syntax expands to `Fn<(&isize,), Output=()>`
--> $DIR/issue-87558.rs:3:6
|
LL | impl Fn(&isize) for Error {
| ^^^^^^^^^^
error: aborting due to 3 previous errors

View File

@ -0,0 +1,21 @@
// check-pass
trait Mirror {
type Assoc;
}
impl<T> Mirror for T {
type Assoc = T;
}
trait Test {}
impl Test for i64 {}
impl Test for u64 {}
fn mirror_me<T: Mirror>(t: T, s: <T as Mirror>::Assoc) where <T as Mirror>::Assoc: Test {}
fn main() {
let mut x = 0;
mirror_me(x, 1);
x = 1i64;
}

View File

@ -0,0 +1,18 @@
// check-pass
// compile-flags: -Ztrait-solver=next
// HIR typeck ends up equating `<_#0i as Add>::Output == _#0i`.
// Want to make sure that we emit an alias-eq goal for this,
// instead of treating it as a type error and bailing.
fn test() {
// fallback
let x = 1 + 2;
}
fn test2() -> u32 {
// expectation from return ty
1 + 2
}
fn main() {}

View File

@ -6,7 +6,7 @@ mod assert {
pub fn is_transmutable<Src, Context, const ASSUME_ALIGNMENT: bool>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME_ALIGNMENT>, //~ ERROR cannot find type `Dst` in this scope
//~^ ERROR mismatched types
//~^ the constant `ASSUME_ALIGNMENT` is not of type `Assume`
{
}
}

View File

@ -4,13 +4,15 @@ error[E0412]: cannot find type `Dst` in this scope
LL | Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME_ALIGNMENT>,
| ^^^ not found in this scope
error[E0308]: mismatched types
--> $DIR/issue-101739-1.rs:8:50
error: the constant `ASSUME_ALIGNMENT` is not of type `Assume`
--> $DIR/issue-101739-1.rs:8:14
|
LL | Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME_ALIGNMENT>,
| ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `BikeshedIntrinsicFrom`
--> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0412.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0412`.

View File

@ -1,5 +1,5 @@
// compile-flags: -Ztrait-solver=next
// known-bug: unknown
// check-pass
fn main() {
(0u8 + 0u8) as char;

View File

@ -1,9 +0,0 @@
error[E0271]: type mismatch resolving `char == <u8 as Add>::Output`
--> $DIR/cast-checks-handling-projections.rs:5:5
|
LL | (0u8 + 0u8) as char;
| ^^^^^^^^^^^ types differ
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.

View File

@ -430,7 +430,7 @@ message = "The Miri subtree was changed"
cc = ["@rust-lang/miri"]
[mentions."src/tools/rust-analyzer"]
cc = ["@rust-lang/wg-rls-2"]
cc = ["@rust-lang/rust-analyzer"]
[mentions."src/tools/rustfmt"]
cc = ["@rust-lang/rustfmt"]