Auto merge of #127403 - compiler-errors:rollup-x2yb5t0, r=compiler-errors
Rollup of 8 pull requests Successful merges: - #123600 (impl PathBuf::add_extension and Path::with_added_extension) - #127107 (Improve dead code analysis) - #127221 (Improve well known value check-cfg diagnostic for the standard library) - #127333 (Split `SolverDelegate` back out from `InferCtxtLike`) - #127363 (Improve readability of some fmt code examples) - #127366 (Use `ControlFlow` results for visitors that are only looking for a single value) - #127368 (Added dots at the sentence ends of rustc AST doc) - #127393 (Remove clubby789 from review rotation) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
51917e2e69
46 changed files with 745 additions and 464 deletions
|
|
@ -4170,6 +4170,7 @@ dependencies = [
|
|||
"rustc_middle",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_type_ir",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ pub enum GenericArgs {
|
|||
AngleBracketed(AngleBracketedArgs),
|
||||
/// The `(A, B)` and `C` in `Foo(A, B) -> C`.
|
||||
Parenthesized(ParenthesizedArgs),
|
||||
/// `(..)` in return type notation
|
||||
/// `(..)` in return type notation.
|
||||
ParenthesizedElided(Span),
|
||||
}
|
||||
|
||||
|
|
@ -197,11 +197,11 @@ impl GenericArgs {
|
|||
/// Concrete argument in the sequence of generic args.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum GenericArg {
|
||||
/// `'a` in `Foo<'a>`
|
||||
/// `'a` in `Foo<'a>`.
|
||||
Lifetime(Lifetime),
|
||||
/// `Bar` in `Foo<Bar>`
|
||||
/// `Bar` in `Foo<Bar>`.
|
||||
Type(P<Ty>),
|
||||
/// `1` in `Foo<1>`
|
||||
/// `1` in `Foo<1>`.
|
||||
Const(AnonConst),
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +355,7 @@ pub enum GenericParamKind {
|
|||
ty: P<Ty>,
|
||||
/// Span of the `const` keyword.
|
||||
kw_span: Span,
|
||||
/// Optional default value for the const generic param
|
||||
/// Optional default value for the const generic param.
|
||||
default: Option<AnonConst>,
|
||||
},
|
||||
}
|
||||
|
|
@ -833,7 +833,7 @@ pub enum PatKind {
|
|||
/// only one rest pattern may occur in the pattern sequences.
|
||||
Rest,
|
||||
|
||||
// A never pattern `!`
|
||||
// A never pattern `!`.
|
||||
Never,
|
||||
|
||||
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
||||
|
|
@ -1122,9 +1122,9 @@ impl LocalKind {
|
|||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Arm {
|
||||
pub attrs: AttrVec,
|
||||
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
|
||||
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`.
|
||||
pub pat: P<Pat>,
|
||||
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
|
||||
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`.
|
||||
pub guard: Option<P<Expr>>,
|
||||
/// Match arm body. Omitted if the pattern is a never pattern.
|
||||
pub body: Option<P<Expr>>,
|
||||
|
|
@ -1355,12 +1355,12 @@ pub struct Closure {
|
|||
pub fn_arg_span: Span,
|
||||
}
|
||||
|
||||
/// Limit types of a range (inclusive or exclusive)
|
||||
/// Limit types of a range (inclusive or exclusive).
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
|
||||
pub enum RangeLimits {
|
||||
/// Inclusive at the beginning, exclusive at the end
|
||||
/// Inclusive at the beginning, exclusive at the end.
|
||||
HalfOpen,
|
||||
/// Inclusive at the beginning and end
|
||||
/// Inclusive at the beginning and end.
|
||||
Closed,
|
||||
}
|
||||
|
||||
|
|
@ -1401,9 +1401,9 @@ pub struct StructExpr {
|
|||
pub enum ExprKind {
|
||||
/// An array (e.g, `[a, b, c, d]`).
|
||||
Array(ThinVec<P<Expr>>),
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
/// Allow anonymous constants from an inline `const` block.
|
||||
ConstBlock(AnonConst),
|
||||
/// A function call
|
||||
/// A function call.
|
||||
///
|
||||
/// The first field resolves to the function itself,
|
||||
/// and the second field is the list of arguments.
|
||||
|
|
@ -1457,7 +1457,7 @@ pub enum ExprKind {
|
|||
/// A block (`'label: { ... }`).
|
||||
Block(P<Block>, Option<Label>),
|
||||
/// An `async` block (`async move { ... }`),
|
||||
/// or a `gen` block (`gen move { ... }`)
|
||||
/// or a `gen` block (`gen move { ... }`).
|
||||
///
|
||||
/// The span is the "decl", which is the header before the body `{ }`
|
||||
/// including the `asyng`/`gen` keywords and possibly `move`.
|
||||
|
|
@ -2157,9 +2157,9 @@ pub enum TyKind {
|
|||
Never,
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
Tup(ThinVec<P<Ty>>),
|
||||
/// An anonymous struct type i.e. `struct { foo: Type }`
|
||||
/// An anonymous struct type i.e. `struct { foo: Type }`.
|
||||
AnonStruct(NodeId, ThinVec<FieldDef>),
|
||||
/// An anonymous union type i.e. `union { bar: Type }`
|
||||
/// An anonymous union type i.e. `union { bar: Type }`.
|
||||
AnonUnion(NodeId, ThinVec<FieldDef>),
|
||||
/// A path (`module::module::...::Type`), optionally
|
||||
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
||||
|
|
@ -2233,9 +2233,9 @@ pub enum TraitObjectSyntax {
|
|||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PreciseCapturingArg {
|
||||
/// Lifetime parameter
|
||||
/// Lifetime parameter.
|
||||
Lifetime(Lifetime),
|
||||
/// Type or const parameter
|
||||
/// Type or const parameter.
|
||||
Arg(Path, NodeId),
|
||||
}
|
||||
|
||||
|
|
@ -2529,11 +2529,11 @@ pub enum Safety {
|
|||
/// Iterator`.
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||
pub enum CoroutineKind {
|
||||
/// `async`, which returns an `impl Future`
|
||||
/// `async`, which returns an `impl Future`.
|
||||
Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// `gen`, which returns an `impl Iterator`
|
||||
/// `gen`, which returns an `impl Iterator`.
|
||||
Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// `async gen`, which returns an `impl AsyncIterator`
|
||||
/// `async gen`, which returns an `impl AsyncIterator`.
|
||||
AsyncGen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
}
|
||||
|
||||
|
|
@ -2750,7 +2750,7 @@ pub struct Variant {
|
|||
pub data: VariantData,
|
||||
/// Explicit discriminant, e.g., `Foo = 1`.
|
||||
pub disr_expr: Option<AnonConst>,
|
||||
/// Is a macro placeholder
|
||||
/// Is a macro placeholder.
|
||||
pub is_placeholder: bool,
|
||||
}
|
||||
|
||||
|
|
@ -3024,19 +3024,19 @@ impl Item {
|
|||
/// `extern` qualifier on a function item or function type.
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
|
||||
pub enum Extern {
|
||||
/// No explicit extern keyword was used
|
||||
/// No explicit extern keyword was used.
|
||||
///
|
||||
/// E.g. `fn foo() {}`
|
||||
/// E.g. `fn foo() {}`.
|
||||
None,
|
||||
/// An explicit extern keyword was used, but with implicit ABI
|
||||
/// An explicit extern keyword was used, but with implicit ABI.
|
||||
///
|
||||
/// E.g. `extern fn foo() {}`
|
||||
/// E.g. `extern fn foo() {}`.
|
||||
///
|
||||
/// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
|
||||
/// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`).
|
||||
Implicit(Span),
|
||||
/// An explicit extern keyword was used with an explicit ABI
|
||||
/// An explicit extern keyword was used with an explicit ABI.
|
||||
///
|
||||
/// E.g. `extern "C" fn foo() {}`
|
||||
/// E.g. `extern "C" fn foo() {}`.
|
||||
Explicit(StrLit, Span),
|
||||
}
|
||||
|
||||
|
|
@ -3055,13 +3055,13 @@ impl Extern {
|
|||
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
|
||||
pub struct FnHeader {
|
||||
/// Whether this is `unsafe`, or has a default safety
|
||||
/// Whether this is `unsafe`, or has a default safety.
|
||||
pub safety: Safety,
|
||||
/// Whether this is `async`, `gen`, or nothing.
|
||||
pub coroutine_kind: Option<CoroutineKind>,
|
||||
/// The `const` keyword, if any
|
||||
pub constness: Const,
|
||||
/// The `extern` keyword and corresponding ABI string, if any
|
||||
/// The `extern` keyword and corresponding ABI string, if any.
|
||||
pub ext: Extern,
|
||||
}
|
||||
|
||||
|
|
@ -3255,7 +3255,7 @@ pub enum ItemKind {
|
|||
///
|
||||
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
|
||||
Trait(Box<Trait>),
|
||||
/// Trait alias
|
||||
/// Trait alias.
|
||||
///
|
||||
/// E.g., `trait Foo = Bar + Quux;`.
|
||||
TraitAlias(Generics, GenericBounds),
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
|||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::borrow_set::TwoPhaseActivation;
|
||||
use crate::borrowck_errors;
|
||||
|
|
@ -784,20 +785,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
/// binding declaration within every scope we inspect.
|
||||
struct Finder {
|
||||
hir_id: hir::HirId,
|
||||
found: bool,
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for Finder {
|
||||
fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result {
|
||||
if pat.hir_id == self.hir_id {
|
||||
self.found = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
hir::intravisit::walk_pat(self, pat);
|
||||
hir::intravisit::walk_pat(self, pat)
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result {
|
||||
if ex.hir_id == self.hir_id {
|
||||
self.found = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
hir::intravisit::walk_expr(self, ex);
|
||||
hir::intravisit::walk_expr(self, ex)
|
||||
}
|
||||
}
|
||||
// The immediate HIR parent of the moved expression. We'll look for it to be a call.
|
||||
|
|
@ -822,9 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
_ => continue,
|
||||
};
|
||||
if let Some(&hir_id) = local_hir_id {
|
||||
let mut finder = Finder { hir_id, found: false };
|
||||
finder.visit_expr(e);
|
||||
if finder.found {
|
||||
if (Finder { hir_id }).visit_expr(e).is_break() {
|
||||
// The current scope includes the declaration of the binding we're accessing, we
|
||||
// can't look up any further for loops.
|
||||
break;
|
||||
|
|
@ -839,9 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::If(cond, ..), ..
|
||||
}) => {
|
||||
let mut finder = Finder { hir_id: expr.hir_id, found: false };
|
||||
finder.visit_expr(cond);
|
||||
if finder.found {
|
||||
if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() {
|
||||
// The expression where the move error happened is in a `while let`
|
||||
// condition Don't suggest clone as it will likely end in an
|
||||
// infinite loop.
|
||||
|
|
@ -1837,7 +1834,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
|
||||
pub struct Holds<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
holds: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
|
||||
|
|
@ -1845,7 +1841,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
if t == self.ty {
|
||||
self.holds = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
|
@ -1863,9 +1859,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
&& rcvr_ty == ty
|
||||
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
||||
&& let inner = inner.peel_refs()
|
||||
&& let mut v = (Holds { ty: inner, holds: false })
|
||||
&& let _ = v.visit_ty(local_ty)
|
||||
&& v.holds
|
||||
&& (Holds { ty: inner }).visit_ty(local_ty).is_break()
|
||||
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
|
||||
{
|
||||
err.span_label(
|
||||
|
|
@ -4325,15 +4319,14 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
|
|||
}
|
||||
|
||||
/// Detect whether one of the provided spans is a statement nested within the top-most visited expr
|
||||
struct ReferencedStatementsVisitor<'a>(&'a [Span], bool);
|
||||
struct ReferencedStatementsVisitor<'a>(&'a [Span]);
|
||||
|
||||
impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> {
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
||||
impl<'v> Visitor<'v> for ReferencedStatementsVisitor<'_> {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
|
||||
match s.kind {
|
||||
hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => {
|
||||
self.1 = true;
|
||||
}
|
||||
_ => {}
|
||||
hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => ControlFlow::Break(()),
|
||||
_ => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4375,9 +4368,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
hir::ExprKind::If(cond, body, None) => {
|
||||
// `if` expressions with no `else` that initialize the binding might be missing an
|
||||
// `else` arm.
|
||||
let mut v = ReferencedStatementsVisitor(self.spans, false);
|
||||
v.visit_expr(body);
|
||||
if v.1 {
|
||||
if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() {
|
||||
self.errors.push((
|
||||
cond.span,
|
||||
format!(
|
||||
|
|
@ -4394,11 +4385,9 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
hir::ExprKind::If(cond, body, Some(other)) => {
|
||||
// `if` expressions where the binding is only initialized in one of the two arms
|
||||
// might be missing a binding initialization.
|
||||
let mut a = ReferencedStatementsVisitor(self.spans, false);
|
||||
a.visit_expr(body);
|
||||
let mut b = ReferencedStatementsVisitor(self.spans, false);
|
||||
b.visit_expr(other);
|
||||
match (a.1, b.1) {
|
||||
let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break();
|
||||
let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break();
|
||||
match (a, b) {
|
||||
(true, true) | (false, false) => {}
|
||||
(true, false) => {
|
||||
if other.span.is_desugaring(DesugaringKind::WhileLoop) {
|
||||
|
|
@ -4437,11 +4426,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
// arms might be missing an initialization.
|
||||
let results: Vec<bool> = arms
|
||||
.iter()
|
||||
.map(|arm| {
|
||||
let mut v = ReferencedStatementsVisitor(self.spans, false);
|
||||
v.visit_arm(arm);
|
||||
v.1
|
||||
})
|
||||
.map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break())
|
||||
.collect();
|
||||
if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
|
||||
for (arm, seen) in arms.iter().zip(results) {
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ fn has_a_default_variant(item: &Annotatable) -> bool {
|
|||
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
// no need to subrecurse.
|
||||
// no need to walk the variant, we are only looking for top level variants
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
use hir::{
|
||||
intravisit::{self, Visitor},
|
||||
|
|
@ -87,14 +89,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
let mut in_param_ty = false;
|
||||
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
|
||||
if let Some(generics) = node.generics() {
|
||||
let mut visitor = AnonConstInParamTyDetector {
|
||||
in_param_ty: false,
|
||||
found_anon_const_in_param_ty: false,
|
||||
ct: hir_id,
|
||||
};
|
||||
let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id };
|
||||
|
||||
visitor.visit_generics(generics);
|
||||
in_param_ty = visitor.found_anon_const_in_param_ty;
|
||||
in_param_ty = visitor.visit_generics(generics).is_break();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -460,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
struct LateBoundRegionsDetector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outer_index: ty::DebruijnIndex,
|
||||
has_late_bound_regions: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
if self.has_late_bound_regions.is_some() {
|
||||
return;
|
||||
}
|
||||
type Result = ControlFlow<Span>;
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
|
||||
match ty.kind {
|
||||
hir::TyKind::BareFn(..) => {
|
||||
self.outer_index.shift_in(1);
|
||||
intravisit::walk_ty(self, ty);
|
||||
let res = intravisit::walk_ty(self, ty);
|
||||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
_ => intravisit::walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
|
||||
if self.has_late_bound_regions.is_some() {
|
||||
return;
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> {
|
||||
self.outer_index.shift_in(1);
|
||||
intravisit::walk_poly_trait_ref(self, tr);
|
||||
let res = intravisit::walk_poly_trait_ref(self, tr);
|
||||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
|
||||
if self.has_late_bound_regions.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> {
|
||||
match self.tcx.named_bound_var(lt.hir_id) {
|
||||
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
|
||||
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
|
||||
if debruijn < self.outer_index => {}
|
||||
if debruijn < self.outer_index =>
|
||||
{
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
Some(
|
||||
rbv::ResolvedArg::LateBound(..)
|
||||
| rbv::ResolvedArg::Free(..)
|
||||
| rbv::ResolvedArg::Error(_),
|
||||
)
|
||||
| None => {
|
||||
self.has_late_bound_regions = Some(lt.ident.span);
|
||||
}
|
||||
| None => ControlFlow::Break(lt.ident.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -513,11 +505,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
generics: &'tcx hir::Generics<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
) -> Option<Span> {
|
||||
let mut visitor = LateBoundRegionsDetector {
|
||||
tcx,
|
||||
outer_index: ty::INNERMOST,
|
||||
has_late_bound_regions: None,
|
||||
};
|
||||
let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST };
|
||||
for param in generics.params {
|
||||
if let GenericParamKind::Lifetime { .. } = param.kind {
|
||||
if tcx.is_late_bound(param.hir_id) {
|
||||
|
|
@ -525,8 +513,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
}
|
||||
}
|
||||
}
|
||||
visitor.visit_fn_decl(decl);
|
||||
visitor.has_late_bound_regions
|
||||
visitor.visit_fn_decl(decl).break_value()
|
||||
}
|
||||
|
||||
let decl = node.fn_decl()?;
|
||||
|
|
@ -536,26 +523,29 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
|
||||
struct AnonConstInParamTyDetector {
|
||||
in_param_ty: bool,
|
||||
found_anon_const_in_param_ty: bool,
|
||||
ct: HirId,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
|
||||
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
|
||||
if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
|
||||
{
|
||||
let prev = self.in_param_ty;
|
||||
self.in_param_ty = true;
|
||||
self.visit_ty(ty);
|
||||
let res = self.visit_ty(ty);
|
||||
self.in_param_ty = prev;
|
||||
res
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
|
||||
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result {
|
||||
if self.in_param_ty && self.ct == c.hir_id {
|
||||
self.found_anon_const_in_param_ty = true;
|
||||
} else {
|
||||
intravisit::walk_anon_const(self, c)
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
intravisit::walk_anon_const(self, c)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,8 +104,6 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
|
||||
type Result = ();
|
||||
|
||||
fn span(&self) -> Span {
|
||||
self.root_cause.span
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ rustc_macros = { path = "../rustc_macros" }
|
|||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
172
compiler/rustc_infer/src/infer/context.rs
Normal file
172
compiler/rustc_infer/src/infer/context.rs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
///! Definition of `InferCtxtLike` from the librarified type layer.
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::InferCtxtLike;
|
||||
|
||||
use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
|
||||
|
||||
impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
|
||||
type Interner = TyCtxt<'tcx>;
|
||||
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn solver_mode(&self) -> ty::solve::SolverMode {
|
||||
match self.intercrate {
|
||||
true => SolverMode::Coherence,
|
||||
false => SolverMode::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex {
|
||||
self.universe()
|
||||
}
|
||||
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex {
|
||||
self.create_next_universe()
|
||||
}
|
||||
|
||||
fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
|
||||
match self.probe_ty_var(vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> {
|
||||
match self.probe_const_var(ct) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||
self.root_var(var)
|
||||
}
|
||||
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.root_const_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> {
|
||||
match self.probe_ty_var(vid) {
|
||||
Ok(ty) => ty,
|
||||
Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_int_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> {
|
||||
match self.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
|
||||
match self.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => {
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types()
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn next_const_infer(&self) -> ty::Const<'tcx> {
|
||||
self.next_const_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
self.fresh_args_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.enter_forall(value, f)
|
||||
}
|
||||
|
||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
|
||||
}
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases_no_trace(lhs, rhs)
|
||||
}
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.resolve_vars_if_possible(value)
|
||||
}
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
|
||||
self.probe(|_| probe())
|
||||
}
|
||||
|
||||
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
|
||||
self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
|
||||
}
|
||||
|
||||
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
|
||||
self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy());
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@ use type_variable::TypeVariableOrigin;
|
|||
|
||||
pub mod at;
|
||||
pub mod canonical;
|
||||
mod context;
|
||||
pub mod error_reporting;
|
||||
pub mod free_regions;
|
||||
mod freshen;
|
||||
|
|
|
|||
|
|
@ -261,10 +261,16 @@ pub(super) fn unexpected_cfg_value(
|
|||
lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
|
||||
};
|
||||
|
||||
// We don't want to suggest adding values to well known names
|
||||
// since those are defined by rustc it-self. Users can still
|
||||
// do it if they want, but should not encourage them.
|
||||
let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
|
||||
// We don't want to encourage people to add values to a well-known names, as these are
|
||||
// defined by rustc/Rust itself. Users can still do this if they wish, but should not be
|
||||
// encouraged to do so.
|
||||
let can_suggest_adding_value = !sess.psess.check_config.well_known_names.contains(&name)
|
||||
// Except when working on rustc or the standard library itself, in which case we want to
|
||||
// suggest adding these cfgs to the "normal" place because of bootstraping reasons. As a
|
||||
// basic heuristic, we use the "cheat" unstable feature enable method and the
|
||||
// non-ui-testing enabled option.
|
||||
|| (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat)
|
||||
&& !sess.opts.unstable_opts.ui_testing);
|
||||
|
||||
let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
|
||||
|
||||
|
|
@ -275,14 +281,14 @@ pub(super) fn unexpected_cfg_value(
|
|||
} else {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
|
||||
}
|
||||
} else if !is_cfg_a_well_know_name {
|
||||
} else if can_suggest_adding_value {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Cargo(help)
|
||||
} else {
|
||||
let help = if !is_cfg_a_well_know_name {
|
||||
let help = if can_suggest_adding_value {
|
||||
Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
|||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner,
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
|
||||
Interner,
|
||||
};
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode};
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
|
||||
pub trait SolverDelegate: Sized {
|
||||
pub trait SolverDelegate:
|
||||
Deref<Target: InferCtxtLike<Interner = <Self as SolverDelegate>::Interner>> + Sized
|
||||
{
|
||||
type Interner: Interner;
|
||||
fn cx(&self) -> Self::Interner;
|
||||
fn cx(&self) -> Self::Interner {
|
||||
(**self).cx()
|
||||
}
|
||||
|
||||
type Span: Copy;
|
||||
|
||||
fn solver_mode(&self) -> SolverMode;
|
||||
|
||||
fn build_with_canonical<V>(
|
||||
cx: Self::Interner,
|
||||
solver_mode: SolverMode,
|
||||
|
|
@ -21,82 +23,12 @@ pub trait SolverDelegate: Sized {
|
|||
where
|
||||
V: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex;
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(
|
||||
&self,
|
||||
vid: ty::FloatVid,
|
||||
) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(
|
||||
&self,
|
||||
vid: ty::ConstVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_effect_var(
|
||||
&self,
|
||||
vid: ty::EffectVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: ty::RegionVid,
|
||||
) -> <Self::Interner as Interner>::Region;
|
||||
|
||||
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
|
||||
|
||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||
fn fresh_args_for_item(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> <Self::Interner as Interner>::GenericArgs;
|
||||
|
||||
fn fresh_var_for_kind_with_span(
|
||||
&self,
|
||||
arg: <Self::Interner as Interner>::GenericArg,
|
||||
span: Self::Span,
|
||||
) -> <Self::Interner as Interner>::GenericArg;
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
) -> T;
|
||||
|
||||
fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U;
|
||||
|
||||
fn relate<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
|
||||
|
||||
// FIXME: Uplift the leak check into this crate.
|
||||
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
|
||||
|
||||
|
|
@ -112,18 +44,6 @@ pub trait SolverDelegate: Sized {
|
|||
unevaluated: ty::UnevaluatedConst<Self::Interner>,
|
||||
) -> Option<<Self::Interner as Interner>::Const>;
|
||||
|
||||
fn sub_regions(
|
||||
&self,
|
||||
sub: <Self::Interner as Interner>::Region,
|
||||
sup: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
fn register_ty_outlives(
|
||||
&self,
|
||||
ty: <Self::Interner as Interner>::Ty,
|
||||
r: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
// FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!
|
||||
fn well_formed_goals(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::delegate::SolverDelegate;
|
|||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EAGER RESOLUTION
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use std::iter;
|
|||
use rustc_index::IndexVec;
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
|||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_type_ir::{self as ty, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_type_ir::Interner;
|
||||
use rustc_type_ir::{InferCtxtLike, Interner};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
|
|
|
|||
|
|
@ -277,7 +277,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
pats: &[hir::PatField<'_>],
|
||||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
ty::Adt(adt, _) => {
|
||||
self.check_def_id(adt.did());
|
||||
adt.variant_of_res(res)
|
||||
}
|
||||
_ => span_bug!(lhs.span, "non-ADT in struct pattern"),
|
||||
};
|
||||
for pat in pats {
|
||||
|
|
@ -297,7 +300,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
dotdot: hir::DotDotPos,
|
||||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
ty::Adt(adt, _) => {
|
||||
self.check_def_id(adt.did());
|
||||
adt.variant_of_res(res)
|
||||
}
|
||||
_ => {
|
||||
self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
|
||||
return;
|
||||
|
|
@ -402,31 +408,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
|
||||
// cause external crate may call such methods to construct values of these types
|
||||
if let Some(local_impl_of) = impl_of.as_local()
|
||||
&& let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(fn_sig) =
|
||||
self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
|
||||
&& matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
|
||||
&& let TyKind::Path(hir::QPath::Resolved(_, path)) =
|
||||
self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
|
||||
&& let Res::Def(def_kind, did) = path.res
|
||||
{
|
||||
match def_kind {
|
||||
// for example, #[derive(Default)] pub struct T(i32);
|
||||
// external crate can call T::default() to construct T,
|
||||
// so that don't ignore impl Default for pub Enum and Structs
|
||||
DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => {
|
||||
return false;
|
||||
}
|
||||
// don't ignore impl Default for Enums,
|
||||
// cause we don't know which variant is constructed
|
||||
DefKind::Enum => return false,
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
|
||||
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
|
||||
{
|
||||
|
|
@ -690,6 +671,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
|||
self.handle_field_pattern_match(pat, res, fields);
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() {
|
||||
self.check_def_id(adt.did());
|
||||
}
|
||||
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
|
||||
self.handle_res(res);
|
||||
}
|
||||
|
|
@ -845,7 +829,7 @@ fn check_item<'tcx>(
|
|||
// mark the method live if the self_ty is public,
|
||||
// or the method is public and may construct self
|
||||
if tcx.visibility(local_def_id).is_public()
|
||||
&& (ty_and_all_fields_are_public || may_construct_self)
|
||||
&& (ty_and_all_fields_are_public || (ty_is_public && may_construct_self))
|
||||
{
|
||||
// if the impl item is public,
|
||||
// and the ty may be constructed or can be constructed in foreign crates,
|
||||
|
|
|
|||
|
|
@ -1,21 +1,18 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
|
||||
use rustc_infer::infer::canonical::{
|
||||
Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues,
|
||||
};
|
||||
use rustc_infer::infer::{
|
||||
BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_infer::traits::{ObligationCause, Reveal};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode};
|
||||
|
||||
use crate::traits::coherence::trait_ref_is_knowable;
|
||||
|
|
@ -48,13 +45,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
|
||||
type Span = Span;
|
||||
|
||||
fn solver_mode(&self) -> ty::solve::SolverMode {
|
||||
match self.intercrate {
|
||||
true => SolverMode::Coherence,
|
||||
false => SolverMode::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_with_canonical<V>(
|
||||
interner: TyCtxt<'tcx>,
|
||||
solver_mode: SolverMode,
|
||||
|
|
@ -74,104 +64,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
(SolverDelegate(infcx), value, vars)
|
||||
}
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex {
|
||||
self.0.universe()
|
||||
}
|
||||
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex {
|
||||
self.0.create_next_universe()
|
||||
}
|
||||
|
||||
fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
|
||||
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
|
||||
// ty infers will give you the universe of the var it resolved to not the universe
|
||||
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
|
||||
// try to print out `?0.1` it will just print `?0`.
|
||||
match self.0.probe_ty_var(vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> {
|
||||
// Same issue as with `universe_of_ty`
|
||||
match self.0.probe_const_var(ct) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||
self.0.root_var(var)
|
||||
}
|
||||
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.0.root_const_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> {
|
||||
match self.0.probe_ty_var(vid) {
|
||||
Ok(ty) => ty,
|
||||
Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
|
||||
self.0.opportunistic_resolve_int_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
|
||||
self.0.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> {
|
||||
match self.0.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
|
||||
match self.0.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => ty::Const::new_infer(
|
||||
self.0.tcx,
|
||||
ty::InferConst::EffectVar(self.0.root_effect_var(vid)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.0
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.0.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.0.defining_opaque_types()
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.0.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn next_const_infer(&self) -> ty::Const<'tcx> {
|
||||
self.0.next_const_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
self.0.fresh_args_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
fn fresh_var_for_kind_with_span(
|
||||
&self,
|
||||
arg: ty::GenericArg<'tcx>,
|
||||
|
|
@ -186,57 +78,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
}
|
||||
}
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.0.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.0.enter_forall(value, f)
|
||||
}
|
||||
|
||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
|
||||
}
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.0
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases_no_trace(lhs, rhs)
|
||||
}
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.0.resolve_vars_if_possible(value)
|
||||
}
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
|
||||
self.0.probe(|_| probe())
|
||||
}
|
||||
|
||||
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
|
||||
self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
|
||||
}
|
||||
|
|
@ -265,14 +106,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
}
|
||||
}
|
||||
|
||||
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
|
||||
self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
|
||||
}
|
||||
|
||||
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
|
||||
self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy());
|
||||
}
|
||||
|
||||
fn well_formed_goals(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
|
|||
|
|
@ -805,10 +805,11 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
|
|||
.unwrap()
|
||||
.contains(&data.trait_ref(self.tcx).def_id);
|
||||
|
||||
// only walk contained types if it's not a super trait
|
||||
if is_supertrait_of_current_trait {
|
||||
ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
|
||||
t.super_visit_with(self) // POSSIBLY reporting an error
|
||||
}
|
||||
}
|
||||
_ => t.super_visit_with(self), // walk contained types, if any
|
||||
|
|
|
|||
|
|
@ -640,8 +640,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
||||
type Result = ();
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
|
||||
|
||||
|
|
|
|||
93
compiler/rustc_type_ir/src/infer_ctxt.rs
Normal file
93
compiler/rustc_type_ir/src/infer_ctxt.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use crate::fold::TypeFoldable;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{Goal, NoSolution, SolverMode};
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
pub trait InferCtxtLike {
|
||||
type Interner: Interner;
|
||||
fn cx(&self) -> Self::Interner;
|
||||
|
||||
fn solver_mode(&self) -> SolverMode;
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex;
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(
|
||||
&self,
|
||||
vid: ty::FloatVid,
|
||||
) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(
|
||||
&self,
|
||||
vid: ty::ConstVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_effect_var(
|
||||
&self,
|
||||
vid: ty::EffectVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: ty::RegionVid,
|
||||
) -> <Self::Interner as Interner>::Region;
|
||||
|
||||
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
|
||||
|
||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||
fn fresh_args_for_item(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> <Self::Interner as Interner>::GenericArgs;
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
) -> T;
|
||||
|
||||
fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U;
|
||||
|
||||
fn relate<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
|
||||
|
||||
fn sub_regions(
|
||||
&self,
|
||||
sub: <Self::Interner as Interner>::Region,
|
||||
sup: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
fn register_ty_outlives(
|
||||
&self,
|
||||
ty: <Self::Interner as Interner>::Ty,
|
||||
r: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ mod const_kind;
|
|||
mod effects;
|
||||
mod flags;
|
||||
mod generic_arg;
|
||||
mod infer_ctxt;
|
||||
mod interner;
|
||||
mod opaque_ty;
|
||||
mod predicate;
|
||||
|
|
@ -56,6 +57,7 @@ pub use const_kind::*;
|
|||
pub use effects::*;
|
||||
pub use flags::*;
|
||||
pub use generic_arg::*;
|
||||
pub use infer_ctxt::*;
|
||||
pub use interner::*;
|
||||
pub use opaque_ty::*;
|
||||
pub use predicate::*;
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ use crate::ascii::Char as AsciiChar;
|
|||
/// ```
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
|
||||
pub trait Default: Sized {
|
||||
/// Returns the "default value" for a type.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -517,7 +517,10 @@ impl Display for Arguments<'_> {
|
|||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
|
||||
/// assert_eq!(
|
||||
/// format!("The origin is: {origin:?}"),
|
||||
/// "The origin is: Point { x: 0, y: 0 }",
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// Manually implementing:
|
||||
|
|
@ -541,7 +544,10 @@ impl Display for Arguments<'_> {
|
|||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
|
||||
/// assert_eq!(
|
||||
/// format!("The origin is: {origin:?}"),
|
||||
/// "The origin is: Point { x: 0, y: 0 }",
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// There are a number of helper methods on the [`Formatter`] struct to help you with manual
|
||||
|
|
@ -582,11 +588,11 @@ impl Display for Arguments<'_> {
|
|||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// assert_eq!(format!("The origin is: {origin:#?}"),
|
||||
/// "The origin is: Point {
|
||||
/// let expected = "The origin is: Point {
|
||||
/// x: 0,
|
||||
/// y: 0,
|
||||
/// }");
|
||||
/// }";
|
||||
/// assert_eq!(format!("The origin is: {origin:#?}"), expected);
|
||||
/// ```
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -738,8 +744,10 @@ pub trait Display {
|
|||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!("(1.987, 2.983)",
|
||||
/// format!("{}", Position { longitude: 1.987, latitude: 2.983, }));
|
||||
/// assert_eq!(
|
||||
/// "(1.987, 2.983)",
|
||||
/// format!("{}", Position { longitude: 1.987, latitude: 2.983, }),
|
||||
/// );
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
|
||||
|
|
|
|||
|
|
@ -1519,6 +1519,74 @@ impl PathBuf {
|
|||
true
|
||||
}
|
||||
|
||||
/// Append [`self.extension`] with `extension`.
|
||||
///
|
||||
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
|
||||
/// returns `true` and updates the extension otherwise.
|
||||
///
|
||||
/// # Caveats
|
||||
///
|
||||
/// The appended `extension` may contain dots and will be used in its entirety,
|
||||
/// but only the part after the final dot will be reflected in
|
||||
/// [`self.extension`].
|
||||
///
|
||||
/// See the examples below.
|
||||
///
|
||||
/// [`self.file_name`]: Path::file_name
|
||||
/// [`self.extension`]: Path::extension
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(path_add_extension)]
|
||||
///
|
||||
/// use std::path::{Path, PathBuf};
|
||||
///
|
||||
/// let mut p = PathBuf::from("/feel/the");
|
||||
///
|
||||
/// p.add_extension("formatted");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted"), p.as_path());
|
||||
///
|
||||
/// p.add_extension("dark.side");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path());
|
||||
///
|
||||
/// p.set_extension("cookie");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path());
|
||||
///
|
||||
/// p.set_extension("");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
|
||||
///
|
||||
/// p.add_extension("");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
|
||||
/// ```
|
||||
#[unstable(feature = "path_add_extension", issue = "127292")]
|
||||
pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
|
||||
self._add_extension(extension.as_ref())
|
||||
}
|
||||
|
||||
fn _add_extension(&mut self, extension: &OsStr) -> bool {
|
||||
let file_name = match self.file_name() {
|
||||
None => return false,
|
||||
Some(f) => f.as_encoded_bytes(),
|
||||
};
|
||||
|
||||
let new = extension;
|
||||
if !new.is_empty() {
|
||||
// truncate until right after the file name
|
||||
// this is necessary for trimming the trailing slash
|
||||
let end_file_name = file_name[file_name.len()..].as_ptr().addr();
|
||||
let start = self.inner.as_encoded_bytes().as_ptr().addr();
|
||||
self.inner.truncate(end_file_name.wrapping_sub(start));
|
||||
|
||||
// append the new extension
|
||||
self.inner.reserve_exact(new.len() + 1);
|
||||
self.inner.push(OsStr::new("."));
|
||||
self.inner.push(new);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Yields a mutable reference to the underlying [`OsString`] instance.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -2656,6 +2724,32 @@ impl Path {
|
|||
new_path
|
||||
}
|
||||
|
||||
/// Creates an owned [`PathBuf`] like `self` but with the extension added.
|
||||
///
|
||||
/// See [`PathBuf::add_extension`] for more details.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(path_add_extension)]
|
||||
///
|
||||
/// use std::path::{Path, PathBuf};
|
||||
///
|
||||
/// let path = Path::new("foo.rs");
|
||||
/// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt"));
|
||||
///
|
||||
/// let path = Path::new("foo.tar.gz");
|
||||
/// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz"));
|
||||
/// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
|
||||
/// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
|
||||
/// ```
|
||||
#[unstable(feature = "path_add_extension", issue = "127292")]
|
||||
pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
|
||||
let mut new_path = self.to_path_buf();
|
||||
new_path.add_extension(extension);
|
||||
new_path
|
||||
}
|
||||
|
||||
/// Produces an iterator over the [`Component`]s of the path.
|
||||
///
|
||||
/// When parsing the path, there is a small amount of normalization:
|
||||
|
|
|
|||
|
|
@ -1401,6 +1401,37 @@ pub fn test_set_extension() {
|
|||
tfe!("/", "foo", "/", false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_add_extension() {
|
||||
macro_rules! tfe (
|
||||
($path:expr, $ext:expr, $expected:expr, $output:expr) => ({
|
||||
let mut p = PathBuf::from($path);
|
||||
let output = p.add_extension($ext);
|
||||
assert!(p.to_str() == Some($expected) && output == $output,
|
||||
"adding extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
|
||||
$path, $ext, $expected, $output,
|
||||
p.to_str().unwrap(), output);
|
||||
});
|
||||
);
|
||||
|
||||
tfe!("foo", "txt", "foo.txt", true);
|
||||
tfe!("foo.bar", "txt", "foo.bar.txt", true);
|
||||
tfe!("foo.bar.baz", "txt", "foo.bar.baz.txt", true);
|
||||
tfe!(".test", "txt", ".test.txt", true);
|
||||
tfe!("foo.txt", "", "foo.txt", true);
|
||||
tfe!("foo", "", "foo", true);
|
||||
tfe!("", "foo", "", false);
|
||||
tfe!(".", "foo", ".", false);
|
||||
tfe!("foo/", "bar", "foo.bar", true);
|
||||
tfe!("foo/.", "bar", "foo.bar", true);
|
||||
tfe!("..", "foo", "..", false);
|
||||
tfe!("foo/..", "bar", "foo/..", false);
|
||||
tfe!("/", "foo", "/", false);
|
||||
|
||||
// edge cases
|
||||
tfe!("/foo.ext////", "bar", "/foo.ext.bar", true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_with_extension() {
|
||||
macro_rules! twe (
|
||||
|
|
@ -1441,6 +1472,49 @@ pub fn test_with_extension() {
|
|||
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.aaa_aaa_aaa");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_with_added_extension() {
|
||||
macro_rules! twe (
|
||||
($input:expr, $extension:expr, $expected:expr) => ({
|
||||
let input = Path::new($input);
|
||||
let output = input.with_added_extension($extension);
|
||||
|
||||
assert!(
|
||||
output.to_str() == Some($expected),
|
||||
"calling Path::new({:?}).with_added_extension({:?}): Expected {:?}, got {:?}",
|
||||
$input, $extension, $expected, output,
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
twe!("foo", "txt", "foo.txt");
|
||||
twe!("foo.bar", "txt", "foo.bar.txt");
|
||||
twe!("foo.bar.baz", "txt", "foo.bar.baz.txt");
|
||||
twe!(".test", "txt", ".test.txt");
|
||||
twe!("foo.txt", "", "foo.txt");
|
||||
twe!("foo", "", "foo");
|
||||
twe!("", "foo", "");
|
||||
twe!(".", "foo", ".");
|
||||
twe!("foo/", "bar", "foo.bar");
|
||||
twe!("foo/.", "bar", "foo.bar");
|
||||
twe!("..", "foo", "..");
|
||||
twe!("foo/..", "bar", "foo/..");
|
||||
twe!("/", "foo", "/");
|
||||
|
||||
// edge cases
|
||||
twe!("/foo.ext////", "bar", "/foo.ext.bar");
|
||||
|
||||
// New extension is smaller than file name
|
||||
twe!("aaa_aaa_aaa", "bbb_bbb", "aaa_aaa_aaa.bbb_bbb");
|
||||
// New extension is greater than file name
|
||||
twe!("bbb_bbb", "aaa_aaa_aaa", "bbb_bbb.aaa_aaa_aaa");
|
||||
|
||||
// New extension is smaller than previous extension
|
||||
twe!("ccc.aaa_aaa_aaa", "bbb_bbb", "ccc.aaa_aaa_aaa.bbb_bbb");
|
||||
// New extension is greater than previous extension
|
||||
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.bbb_bbb.aaa_aaa_aaa");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq_receivers() {
|
||||
use crate::borrow::Cow;
|
||||
|
|
|
|||
|
|
@ -241,11 +241,3 @@ impl Parse for QueryGroup {
|
|||
Ok(QueryGroup { group_path })
|
||||
}
|
||||
}
|
||||
|
||||
struct Nothing;
|
||||
|
||||
impl Parse for Nothing {
|
||||
fn parse(_input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
Ok(Nothing)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,18 +17,21 @@ mod submod {
|
|||
// if any of these are implemented without global calls for any
|
||||
// function calls, then being in a submodule will (correctly)
|
||||
// cause errors about unrecognised module `std` (or `extra`)
|
||||
#[allow(dead_code)]
|
||||
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
|
||||
enum A {
|
||||
A1(usize),
|
||||
A2(isize),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
|
||||
struct B {
|
||||
x: usize,
|
||||
y: isize,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
|
||||
struct C(usize, isize);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pub const s: u8 = 1;
|
|||
pub const state: u8 = 1;
|
||||
pub const cmp: u8 = 1;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Ord, Eq, PartialOrd, PartialEq, Debug, Decodable, Encodable, Hash)]
|
||||
struct Foo {}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub trait Foo {
|
|||
fn foo() where [(); Self::ASSOC_C]:;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Bar<const N: &'static ()>;
|
||||
impl<const N: &'static ()> Foo for Bar<N> {
|
||||
const ASSOC_C: usize = 3;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(adt_const_params, generic_const_exprs)]
|
||||
#![allow(incomplete_features, unused_variables)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct F<const S: &'static str>;
|
||||
impl<const S: &'static str> X for F<{ S }> {
|
||||
const W: usize = 3;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct S<T>(T);
|
||||
#[allow(dead_code)]
|
||||
struct S2;
|
||||
|
||||
impl<T: Default> Default for S<T> {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct S<T>(T);
|
||||
#[allow(dead_code)]
|
||||
struct S2;
|
||||
|
||||
impl<T: Default> impl Default for S<T> {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
error: unexpected `impl` keyword
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:6:18
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:8:18
|
||||
|
|
||||
LL | impl<T: Default> impl Default for S<T> {
|
||||
| ^^^^^ help: remove the extra `impl`
|
||||
|
|
||||
note: this is parsed as an `impl Trait` type, but a trait is expected at this position
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:6:18
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:8:18
|
||||
|
|
||||
LL | impl<T: Default> impl Default for S<T> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: unexpected `impl` keyword
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:12:6
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:14:6
|
||||
|
|
||||
LL | impl impl Default for S2 {
|
||||
| ^^^^^ help: remove the extra `impl`
|
||||
|
|
||||
note: this is parsed as an `impl Trait` type, but a trait is expected at this position
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:12:6
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:14:6
|
||||
|
|
||||
LL | impl impl Default for S2 {
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#![deny(dead_code)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Foo {
|
||||
#[allow(dead_code)]
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
#![deny(dead_code)]
|
||||
|
||||
struct Foo(u8); //~ ERROR struct `Foo` is never constructed
|
||||
|
||||
enum Bar { //~ ERROR enum `Bar` is never used
|
||||
Var1(u8),
|
||||
Var2(u8),
|
||||
}
|
||||
|
||||
pub trait Tr1 {
|
||||
fn f1() -> Self;
|
||||
}
|
||||
|
||||
impl Tr1 for Foo {
|
||||
fn f1() -> Foo {
|
||||
let f = Foo(0);
|
||||
let Foo(tag) = f;
|
||||
Foo(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl Tr1 for Bar {
|
||||
fn f1() -> Bar {
|
||||
let b = Bar::Var1(0);
|
||||
let b = if let Bar::Var1(_) = b {
|
||||
Bar::Var1(0)
|
||||
} else {
|
||||
Bar::Var2(0)
|
||||
};
|
||||
match b {
|
||||
Bar::Var1(_) => Bar::Var2(0),
|
||||
Bar::Var2(_) => Bar::Var1(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error: struct `Foo` is never constructed
|
||||
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8
|
||||
|
|
||||
LL | struct Foo(u8);
|
||||
| ^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: enum `Bar` is never used
|
||||
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6
|
||||
|
|
||||
LL | enum Bar {
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
//@ check-pass
|
||||
|
||||
#![deny(dead_code)]
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum RecordField {
|
||||
Target = 1,
|
||||
Level,
|
||||
Module,
|
||||
File,
|
||||
Line,
|
||||
NumArgs,
|
||||
}
|
||||
|
||||
unsafe trait Pod {}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct RecordFieldWrapper(RecordField);
|
||||
|
||||
unsafe impl Pod for RecordFieldWrapper {}
|
||||
|
||||
fn try_read<T: Pod>(buf: &[u8]) -> T {
|
||||
unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) }
|
||||
}
|
||||
|
||||
pub fn foo(buf: &[u8]) -> RecordField {
|
||||
let RecordFieldWrapper(tag) = try_read(buf);
|
||||
tag
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
#![deny(dead_code)]
|
||||
|
||||
struct T1; //~ ERROR struct `T1` is never constructed
|
||||
pub struct T2(i32); //~ ERROR struct `T2` is never constructed
|
||||
struct T3;
|
||||
struct T2; //~ ERROR struct `T2` is never constructed
|
||||
pub struct T3(i32); //~ ERROR struct `T3` is never constructed
|
||||
pub struct T4(i32); //~ ERROR field `0` is never read
|
||||
|
||||
trait Trait1 { //~ ERROR trait `Trait1` is never used
|
||||
const UNUSED: i32;
|
||||
|
|
@ -11,13 +12,13 @@ trait Trait1 { //~ ERROR trait `Trait1` is never used
|
|||
}
|
||||
|
||||
pub trait Trait2 {
|
||||
const USED: i32;
|
||||
fn used(&self) {}
|
||||
const MAY_USED: i32;
|
||||
fn may_used(&self) {}
|
||||
}
|
||||
|
||||
pub trait Trait3 {
|
||||
const USED: i32;
|
||||
fn construct_self() -> Self;
|
||||
const MAY_USED: i32;
|
||||
fn may_used() -> Self;
|
||||
}
|
||||
|
||||
impl Trait1 for T1 {
|
||||
|
|
@ -29,24 +30,35 @@ impl Trait1 for T1 {
|
|||
|
||||
impl Trait1 for T2 {
|
||||
const UNUSED: i32 = 0;
|
||||
fn construct_self() -> Self {
|
||||
T2(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Trait2 for T1 {
|
||||
const USED: i32 = 0;
|
||||
}
|
||||
|
||||
impl Trait2 for T2 {
|
||||
const USED: i32 = 0;
|
||||
}
|
||||
|
||||
impl Trait3 for T3 {
|
||||
const USED: i32 = 0;
|
||||
fn construct_self() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Trait2 for T1 {
|
||||
const MAY_USED: i32 = 0;
|
||||
}
|
||||
|
||||
impl Trait2 for T2 {
|
||||
const MAY_USED: i32 = 0;
|
||||
}
|
||||
|
||||
impl Trait2 for T3 {
|
||||
const MAY_USED: i32 = 0;
|
||||
}
|
||||
|
||||
impl Trait3 for T2 {
|
||||
const MAY_USED: i32 = 0;
|
||||
fn may_used() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Trait3 for T4 {
|
||||
const MAY_USED: i32 = 0;
|
||||
fn may_used() -> Self {
|
||||
T4(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -11,16 +11,32 @@ LL | #![deny(dead_code)]
|
|||
| ^^^^^^^^^
|
||||
|
||||
error: struct `T2` is never constructed
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:12
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:8
|
||||
|
|
||||
LL | pub struct T2(i32);
|
||||
LL | struct T2;
|
||||
| ^^
|
||||
|
||||
error: struct `T3` is never constructed
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:12
|
||||
|
|
||||
LL | pub struct T3(i32);
|
||||
| ^^
|
||||
|
||||
error: field `0` is never read
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:6:15
|
||||
|
|
||||
LL | pub struct T4(i32);
|
||||
| -- ^^^
|
||||
| |
|
||||
| field in this struct
|
||||
|
|
||||
= help: consider removing this field
|
||||
|
||||
error: trait `Trait1` is never used
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:8:7
|
||||
|
|
||||
LL | trait Trait1 {
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -22,4 +22,5 @@ pub struct T2 {
|
|||
|
||||
fn main() {
|
||||
let _x: Used = Default::default();
|
||||
let _e: E = Default::default();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ error: struct `T` is never constructed
|
|||
LL | struct T;
|
||||
| ^
|
||||
|
|
||||
= note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unused-struct-derive-default.rs:1:9
|
||||
|
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Foo;
|
||||
|
||||
impl From<i32> for Foo {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Foo;
|
||||
|
||||
fn From<i32> for Foo {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: you might have meant to write `impl` instead of `fn`
|
||||
--> $DIR/issue-105366.rs:5:1
|
||||
--> $DIR/issue-105366.rs:6:1
|
||||
|
|
||||
LL | fn From<i32> for Foo {
|
||||
| ^^
|
||||
|
|
|
|||
|
|
@ -952,7 +952,6 @@ bootstrap = [
|
|||
"@Mark-Simulacrum",
|
||||
"@albertlarsan68",
|
||||
"@onur-ozkan",
|
||||
"@clubby789",
|
||||
"@kobzol",
|
||||
]
|
||||
infra-ci = [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue