Auto merge of #105365 - matthiaskrgr:rollup-g0mrrt7, r=matthiaskrgr
Rollup of 11 pull requests Successful merges: - #104439 (Add prototype to generate `COPYRIGHT` from REUSE metadata) - #105005 (On E0195 point at where clause lifetime bounds) - #105098 (propagate the error from parsing enum variant to the parser and emit out) - #105243 (remove no-op 'let _ = ') - #105254 (Recurse into nested impl-trait when computing variance.) - #105287 (Synthesize substitutions for bad auto traits in dyn types) - #105310 (Be more careful about unresolved exprs in suggestion) - #105318 (Make `get_impl_future_output_ty` work with AFIT) - #105339 (support `ConstKind::Expr` in `is_const_evaluatable` and `WfPredicates::compute`) - #105340 (Avoid ICE by accounting for missing type) - #105342 (Make `note_obligation_cause_code` take a `impl ToPredicate` for predicate) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b6852428a8
59 changed files with 1406 additions and 124 deletions
77
Cargo.lock
77
Cargo.lock
|
@ -581,6 +581,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
"time",
|
"time",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
@ -730,6 +731,16 @@ dependencies = [
|
||||||
"rustc-semver",
|
"rustc-semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "collect-license-metadata"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"spdx-rs",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color-eyre"
|
name = "color-eyre"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
|
@ -1552,6 +1563,15 @@ dependencies = [
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generate-copyright"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.4"
|
version = "0.14.4"
|
||||||
|
@ -4864,6 +4884,35 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spdx-expression"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d7ac03c67c572d85049d6db815e20a4a19b41b3d5cca732ac582342021ad77"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spdx-rs"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3c02f6eb7e7b4100c272f685a9ccaccaab302324e8c7ec3e2ee72340fb29ff3"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"log",
|
||||||
|
"nom",
|
||||||
|
"serde",
|
||||||
|
"spdx-expression",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
|
"thiserror",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -4967,6 +5016,25 @@ version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.24.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.24.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.102"
|
version = "1.0.102"
|
||||||
|
@ -5596,6 +5664,15 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
|
checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -39,6 +39,8 @@ members = [
|
||||||
"src/tools/bump-stage0",
|
"src/tools/bump-stage0",
|
||||||
"src/tools/replace-version-placeholder",
|
"src/tools/replace-version-placeholder",
|
||||||
"src/tools/lld-wrapper",
|
"src/tools/lld-wrapper",
|
||||||
|
"src/tools/collect-license-metadata",
|
||||||
|
"src/tools/generate-copyright",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = [
|
exclude = [
|
||||||
|
|
|
@ -121,9 +121,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
|
||||||
pub(super) fn prove_predicates(
|
pub(super) fn prove_predicates(
|
||||||
&mut self,
|
&mut self,
|
||||||
predicates: impl IntoIterator<
|
predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>,
|
||||||
Item = impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug,
|
|
||||||
>,
|
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
category: ConstraintCategory<'tcx>,
|
category: ConstraintCategory<'tcx>,
|
||||||
) {
|
) {
|
||||||
|
@ -135,7 +133,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
pub(super) fn prove_predicate(
|
pub(super) fn prove_predicate(
|
||||||
&mut self,
|
&mut self,
|
||||||
predicate: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug,
|
predicate: impl ToPredicate<'tcx> + std::fmt::Debug,
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
category: ConstraintCategory<'tcx>,
|
category: ConstraintCategory<'tcx>,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -17,6 +17,8 @@ hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
|
||||||
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
|
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
|
||||||
.label = lifetimes do not match {$item_kind} in trait
|
.label = lifetimes do not match {$item_kind} in trait
|
||||||
.generics_label = lifetimes in impl do not match this {$item_kind} in trait
|
.generics_label = lifetimes in impl do not match this {$item_kind} in trait
|
||||||
|
.where_label = this `where` clause might not match the one in the trait
|
||||||
|
.bounds_label = this bound might be missing in the impl
|
||||||
|
|
||||||
hir_analysis_drop_impl_on_wrong_item =
|
hir_analysis_drop_impl_on_wrong_item =
|
||||||
the `Drop` trait may only be implemented for local structs, enums, and unions
|
the `Drop` trait may only be implemented for local structs, enums, and unions
|
||||||
|
|
|
@ -751,17 +751,45 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
||||||
.get_generics(impl_m.def_id.expect_local())
|
.get_generics(impl_m.def_id.expect_local())
|
||||||
.expect("expected impl item to have generics or else we can't compare them")
|
.expect("expected impl item to have generics or else we can't compare them")
|
||||||
.span;
|
.span;
|
||||||
let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() {
|
|
||||||
Some(
|
|
||||||
tcx.hir()
|
|
||||||
.get_generics(local_def_id)
|
|
||||||
.expect("expected trait item to have generics or else we can't compare them")
|
|
||||||
.span,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let mut generics_span = None;
|
||||||
|
let mut bounds_span = vec![];
|
||||||
|
let mut where_span = None;
|
||||||
|
if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
|
||||||
|
&& let Some(trait_generics) = trait_node.generics()
|
||||||
|
{
|
||||||
|
generics_span = Some(trait_generics.span);
|
||||||
|
// FIXME: we could potentially look at the impl's bounds to not point at bounds that
|
||||||
|
// *are* present in the impl.
|
||||||
|
for p in trait_generics.predicates {
|
||||||
|
if let hir::WherePredicate::BoundPredicate(pred) = p {
|
||||||
|
for b in pred.bounds {
|
||||||
|
if let hir::GenericBound::Outlives(lt) = b {
|
||||||
|
bounds_span.push(lt.ident.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
|
||||||
|
&& let Some(impl_generics) = impl_node.generics()
|
||||||
|
{
|
||||||
|
let mut impl_bounds = 0;
|
||||||
|
for p in impl_generics.predicates {
|
||||||
|
if let hir::WherePredicate::BoundPredicate(pred) = p {
|
||||||
|
for b in pred.bounds {
|
||||||
|
if let hir::GenericBound::Outlives(_) = b {
|
||||||
|
impl_bounds += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if impl_bounds == bounds_span.len() {
|
||||||
|
bounds_span = vec![];
|
||||||
|
} else if impl_generics.has_where_clause_predicates {
|
||||||
|
where_span = Some(impl_generics.where_clause_span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let reported = tcx
|
let reported = tcx
|
||||||
.sess
|
.sess
|
||||||
.create_err(LifetimesOrBoundsMismatchOnTrait {
|
.create_err(LifetimesOrBoundsMismatchOnTrait {
|
||||||
|
@ -769,9 +797,10 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
||||||
item_kind: assoc_item_kind_str(impl_m),
|
item_kind: assoc_item_kind_str(impl_m),
|
||||||
ident: impl_m.ident(tcx),
|
ident: impl_m.ident(tcx),
|
||||||
generics_span,
|
generics_span,
|
||||||
|
bounds_span,
|
||||||
|
where_span,
|
||||||
})
|
})
|
||||||
.emit_unless(delay);
|
.emit_unless(delay);
|
||||||
|
|
||||||
return Err(reported);
|
return Err(reported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,10 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label(generics_label)]
|
#[label(generics_label)]
|
||||||
pub generics_span: Option<Span>,
|
pub generics_span: Option<Span>,
|
||||||
|
#[label(where_label)]
|
||||||
|
pub where_span: Option<Span>,
|
||||||
|
#[label(bounds_label)]
|
||||||
|
pub bounds_span: Vec<Span>,
|
||||||
pub item_kind: &'static str,
|
pub item_kind: &'static str,
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ use rustc_arena::DroplessArena;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable};
|
use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
|
||||||
|
use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
/// Defines the `TermsContext` basically houses an arena where we can
|
/// Defines the `TermsContext` basically houses an arena where we can
|
||||||
|
@ -75,11 +76,30 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||||
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
|
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
|
||||||
// ```
|
// ```
|
||||||
// we may not use `'c` in the hidden type.
|
// we may not use `'c` in the hidden type.
|
||||||
struct OpaqueTypeLifetimeCollector {
|
struct OpaqueTypeLifetimeCollector<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
root_def_id: DefId,
|
||||||
variances: Vec<ty::Variance>,
|
variances: Vec<ty::Variance>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector {
|
impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> {
|
||||||
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
|
fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow<!> {
|
||||||
|
if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) {
|
||||||
|
let child_variances = self.tcx.variances_of(def_id);
|
||||||
|
for (a, v) in substs.iter().zip(child_variances) {
|
||||||
|
if *v != ty::Bivariant {
|
||||||
|
a.visit_with(self)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlow::CONTINUE
|
||||||
|
} else {
|
||||||
|
substs.visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
|
||||||
#[instrument(level = "trace", skip(self), ret)]
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
|
if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
|
||||||
|
@ -87,6 +107,19 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||||
}
|
}
|
||||||
r.super_visit_with(self)
|
r.super_visit_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
match t.kind() {
|
||||||
|
ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs),
|
||||||
|
ty::Projection(proj)
|
||||||
|
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
|
||||||
|
{
|
||||||
|
self.visit_opaque(proj.item_def_id, proj.substs)
|
||||||
|
}
|
||||||
|
_ => t.super_visit_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
|
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
|
||||||
|
@ -111,7 +144,8 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut collector = OpaqueTypeLifetimeCollector { variances };
|
let mut collector =
|
||||||
|
OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
|
||||||
let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
|
let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
|
||||||
for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
|
for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
|
||||||
let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
|
let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
|
||||||
|
|
|
@ -1482,15 +1482,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ident_name: Symbol,
|
ident_name: Symbol,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This really should be taking scoping, etc into account.
|
||||||
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
||||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
||||||
if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind {
|
if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind
|
||||||
if let Binding(_, _, ident, ..) = pat.kind &&
|
&& let Binding(_, _, ident, ..) = pat.kind
|
||||||
ident.name == self.ident_name {
|
&& ident.name == self.ident_name
|
||||||
self.result = *init;
|
{
|
||||||
}
|
self.result = *init;
|
||||||
|
} else {
|
||||||
|
hir::intravisit::walk_stmt(self, ex);
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_stmt(self, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1498,9 +1500,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
visitor.visit_body(&body);
|
visitor.visit_body(&body);
|
||||||
|
|
||||||
let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
|
let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
|
||||||
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
|
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
|
||||||
let Some(expr) = visitor.result {
|
&& let Some(expr) = visitor.result
|
||||||
let self_ty = self.node_ty(expr.hir_id);
|
&& let Some(self_ty) = self.node_ty_opt(expr.hir_id)
|
||||||
|
{
|
||||||
let probe = self.lookup_probe(
|
let probe = self.lookup_probe(
|
||||||
seg2.ident,
|
seg2.ident,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
@ -1513,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
|
sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
|
||||||
"you may have meant to call an instance method",
|
"you may have meant to call an instance method",
|
||||||
".".to_string(),
|
".".to_string(),
|
||||||
Applicability::MaybeIncorrect
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,7 +341,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
impl<'tcx> InferCtxt<'tcx> {
|
||||||
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||||
let ty::Opaque(def_id, substs) = *ty.kind() else { return None; };
|
let (def_id, substs) = match *ty.kind() {
|
||||||
|
ty::Opaque(def_id, substs) => (def_id, substs),
|
||||||
|
ty::Projection(data)
|
||||||
|
if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
|
||||||
|
{
|
||||||
|
(data.item_def_id, data.substs)
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||||
|
|
|
@ -101,6 +101,20 @@ impl GenericParamDef {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_error<'tcx>(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
preceding_substs: &[ty::GenericArg<'tcx>],
|
||||||
|
) -> ty::GenericArg<'tcx> {
|
||||||
|
match &self.kind {
|
||||||
|
ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
|
||||||
|
ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(),
|
||||||
|
ty::GenericParamDefKind::Const { .. } => {
|
||||||
|
tcx.const_error(tcx.bound_type_of(self.def_id).subst(tcx, preceding_substs)).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -1150,8 +1150,8 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToPredicate<'tcx, Predicate> {
|
pub trait ToPredicate<'tcx, P = Predicate<'tcx>> {
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate;
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, T> ToPredicate<'tcx, T> for T {
|
impl<'tcx, T> ToPredicate<'tcx, T> for T {
|
||||||
|
@ -1160,21 +1160,21 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, PredicateKind<'tcx>> {
|
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
tcx.mk_predicate(self)
|
tcx.mk_predicate(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Clause<'tcx> {
|
impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self)))
|
tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
|
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
|
let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
|
||||||
|
@ -1193,25 +1193,25 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTraitPredicate<'tcx> {
|
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx)
|
self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyRegionOutlivesPredicate<'tcx> {
|
impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx)
|
self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTypeOutlivesPredicate<'tcx> {
|
impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx)
|
self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyProjectionPredicate<'tcx> {
|
impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx)
|
self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -722,8 +722,17 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
|
||||||
self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
|
self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
|
||||||
}
|
}
|
||||||
ExistentialPredicate::AutoTrait(did) => {
|
ExistentialPredicate::AutoTrait(did) => {
|
||||||
let trait_ref = self.rebind(tcx.mk_trait_ref(did, [self_ty]));
|
let generics = tcx.generics_of(did);
|
||||||
trait_ref.without_const().to_predicate(tcx)
|
let trait_ref = if generics.params.len() == 1 {
|
||||||
|
tcx.mk_trait_ref(did, [self_ty])
|
||||||
|
} else {
|
||||||
|
// If this is an ill-formed auto trait, then synthesize
|
||||||
|
// new error substs for the missing generics.
|
||||||
|
let err_substs =
|
||||||
|
ty::InternalSubsts::extend_with_error(tcx, did, &[self_ty.into()]);
|
||||||
|
tcx.mk_trait_ref(did, err_substs)
|
||||||
|
};
|
||||||
|
self.rebind(trait_ref).without_const().to_predicate(tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,6 +352,22 @@ impl<'tcx> InternalSubsts<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extend an `original_substs` list to the full number of substs expected by `def_id`,
|
||||||
|
// filling in the missing parameters with error ty/ct or 'static regions.
|
||||||
|
pub fn extend_with_error(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
original_substs: &[GenericArg<'tcx>],
|
||||||
|
) -> SubstsRef<'tcx> {
|
||||||
|
ty::InternalSubsts::for_item(tcx, def_id, |def, substs| {
|
||||||
|
if let Some(subst) = original_substs.get(def.index as usize) {
|
||||||
|
*subst
|
||||||
|
} else {
|
||||||
|
def.to_error(tcx, substs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx {
|
pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx {
|
||||||
self.iter()
|
self.iter()
|
||||||
|
|
|
@ -1414,7 +1414,10 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
Ok((Some(vr), TrailingToken::MaybeComma))
|
Ok((Some(vr), TrailingToken::MaybeComma))
|
||||||
},
|
},
|
||||||
)
|
).map_err(|mut err|{
|
||||||
|
err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
|
||||||
|
err
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `struct Foo { ... }`.
|
/// Parses `struct Foo { ... }`.
|
||||||
|
|
|
@ -943,6 +943,10 @@ impl<'a> Parser<'a> {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Parsing failed, therefore it must be something more serious
|
// Parsing failed, therefore it must be something more serious
|
||||||
// than just a missing separator.
|
// than just a missing separator.
|
||||||
|
for xx in &e.children {
|
||||||
|
// propagate the help message from sub error 'e' to main error 'expect_err;
|
||||||
|
expect_err.children.push(xx.clone());
|
||||||
|
}
|
||||||
expect_err.emit();
|
expect_err.emit();
|
||||||
|
|
||||||
e.cancel();
|
e.cancel();
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub fn codegen_select_candidate<'tcx>(
|
||||||
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
|
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
|
||||||
for err in errors {
|
for err in errors {
|
||||||
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
|
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
|
||||||
infcx.err_ctxt().report_overflow_error_cycle(&cycle);
|
infcx.err_ctxt().report_overflow_obligation_cycle(&cycle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(CodegenObligationError::FulfillmentError);
|
return Err(CodegenObligationError::FulfillmentError);
|
||||||
|
|
|
@ -25,15 +25,13 @@ use crate::traits::ObligationCtxt;
|
||||||
#[instrument(skip(infcx), level = "debug")]
|
#[instrument(skip(infcx), level = "debug")]
|
||||||
pub fn is_const_evaluatable<'tcx>(
|
pub fn is_const_evaluatable<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
ct: ty::Const<'tcx>,
|
unexpanded_ct: ty::Const<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<(), NotConstEvaluatable> {
|
) -> Result<(), NotConstEvaluatable> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let uv = match ct.kind() {
|
match unexpanded_ct.kind() {
|
||||||
ty::ConstKind::Unevaluated(uv) => uv,
|
ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (),
|
||||||
// FIXME(generic_const_exprs): this seems wrong but I couldn't find a way to get this to trigger
|
|
||||||
ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"),
|
|
||||||
ty::ConstKind::Param(_)
|
ty::ConstKind::Param(_)
|
||||||
| ty::ConstKind::Bound(_, _)
|
| ty::ConstKind::Bound(_, _)
|
||||||
| ty::ConstKind::Placeholder(_)
|
| ty::ConstKind::Placeholder(_)
|
||||||
|
@ -43,7 +41,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
if tcx.features().generic_const_exprs {
|
if tcx.features().generic_const_exprs {
|
||||||
let ct = tcx.expand_abstract_consts(ct);
|
let ct = tcx.expand_abstract_consts(unexpanded_ct);
|
||||||
|
|
||||||
let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
|
let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
|
||||||
tcx.def_kind(uv.def.did) == DefKind::AnonConst
|
tcx.def_kind(uv.def.did) == DefKind::AnonConst
|
||||||
|
@ -62,18 +60,40 @@ pub fn is_const_evaluatable<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
match unexpanded_ct.kind() {
|
||||||
match concrete {
|
ty::ConstKind::Expr(_) => {
|
||||||
Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error(
|
// FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but
|
||||||
infcx
|
// currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it
|
||||||
.tcx
|
// is evaluatable or not. For now we just ICE until this is implemented this.
|
||||||
.sess
|
Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug(
|
||||||
.delay_span_bug(span, "Missing value for constant, but no error reported?"),
|
span,
|
||||||
)),
|
"evaluating `ConstKind::Expr` is not currently supported",
|
||||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
)))
|
||||||
Ok(_) => Ok(()),
|
}
|
||||||
|
ty::ConstKind::Unevaluated(uv) => {
|
||||||
|
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||||
|
match concrete {
|
||||||
|
Err(ErrorHandled::TooGeneric) => {
|
||||||
|
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
|
||||||
|
span,
|
||||||
|
"Missing value for constant, but no error reported?",
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let uv = match unexpanded_ct.kind() {
|
||||||
|
ty::ConstKind::Unevaluated(uv) => uv,
|
||||||
|
ty::ConstKind::Expr(_) => {
|
||||||
|
bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled")
|
||||||
|
}
|
||||||
|
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
|
||||||
|
};
|
||||||
|
|
||||||
// FIXME: We should only try to evaluate a given constant here if it is fully concrete
|
// FIXME: We should only try to evaluate a given constant here if it is fully concrete
|
||||||
// as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
|
// as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
|
||||||
//
|
//
|
||||||
|
@ -92,7 +112,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||||
&& satisfied_from_param_env(
|
&& satisfied_from_param_env(
|
||||||
tcx,
|
tcx,
|
||||||
infcx,
|
infcx,
|
||||||
tcx.expand_abstract_consts(ct),
|
tcx.expand_abstract_consts(unexpanded_ct),
|
||||||
param_env,
|
param_env,
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
|
@ -152,6 +172,7 @@ fn satisfied_from_param_env<'tcx>(
|
||||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||||
type BreakTy = ();
|
type BreakTy = ();
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
debug!("is_const_evaluatable: candidate={:?}", c);
|
||||||
if let Ok(()) = self.infcx.commit_if_ok(|_| {
|
if let Ok(()) = self.infcx.commit_if_ok(|_| {
|
||||||
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
|
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
|
||||||
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
|
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
|
||||||
|
@ -187,7 +208,7 @@ fn satisfied_from_param_env<'tcx>(
|
||||||
let result = b_ct.visit_with(&mut v);
|
let result = b_ct.visit_with(&mut v);
|
||||||
|
|
||||||
if let ControlFlow::Break(()) = result {
|
if let ControlFlow::Break(()) = result {
|
||||||
debug!("is_const_evaluatable: abstract_const ~~> ok");
|
debug!("is_const_evaluatable: yes");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,5 +216,6 @@ fn satisfied_from_param_env<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("is_const_evaluatable: no");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,16 +99,12 @@ pub trait InferCtxtExt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TypeErrCtxtExt<'tcx> {
|
pub trait TypeErrCtxtExt<'tcx> {
|
||||||
fn report_fulfillment_errors(
|
|
||||||
&self,
|
|
||||||
errors: &[FulfillmentError<'tcx>],
|
|
||||||
body_id: Option<hir::BodyId>,
|
|
||||||
) -> ErrorGuaranteed;
|
|
||||||
|
|
||||||
fn report_overflow_error<T>(
|
fn report_overflow_error<T>(
|
||||||
&self,
|
&self,
|
||||||
obligation: &Obligation<'tcx, T>,
|
predicate: &T,
|
||||||
|
span: Span,
|
||||||
suggest_increasing_limit: bool,
|
suggest_increasing_limit: bool,
|
||||||
|
mutate: impl FnOnce(&mut Diagnostic),
|
||||||
) -> !
|
) -> !
|
||||||
where
|
where
|
||||||
T: fmt::Display
|
T: fmt::Display
|
||||||
|
@ -116,9 +112,23 @@ pub trait TypeErrCtxtExt<'tcx> {
|
||||||
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
||||||
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
|
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
|
||||||
|
|
||||||
|
fn report_fulfillment_errors(
|
||||||
|
&self,
|
||||||
|
errors: &[FulfillmentError<'tcx>],
|
||||||
|
body_id: Option<hir::BodyId>,
|
||||||
|
) -> ErrorGuaranteed;
|
||||||
|
|
||||||
|
fn report_overflow_obligation<T>(
|
||||||
|
&self,
|
||||||
|
obligation: &Obligation<'tcx, T>,
|
||||||
|
suggest_increasing_limit: bool,
|
||||||
|
) -> !
|
||||||
|
where
|
||||||
|
T: ToPredicate<'tcx> + Clone;
|
||||||
|
|
||||||
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
|
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
|
||||||
|
|
||||||
fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
|
fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
|
||||||
|
|
||||||
/// The `root_obligation` parameter should be the `root_obligation` field
|
/// The `root_obligation` parameter should be the `root_obligation` field
|
||||||
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
|
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
|
||||||
|
@ -458,8 +468,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
/// occurrences in any case.
|
/// occurrences in any case.
|
||||||
fn report_overflow_error<T>(
|
fn report_overflow_error<T>(
|
||||||
&self,
|
&self,
|
||||||
obligation: &Obligation<'tcx, T>,
|
predicate: &T,
|
||||||
|
span: Span,
|
||||||
suggest_increasing_limit: bool,
|
suggest_increasing_limit: bool,
|
||||||
|
mutate: impl FnOnce(&mut Diagnostic),
|
||||||
) -> !
|
) -> !
|
||||||
where
|
where
|
||||||
T: fmt::Display
|
T: fmt::Display
|
||||||
|
@ -467,8 +479,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
||||||
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
|
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
let predicate = self.resolve_vars_if_possible(obligation.predicate.clone());
|
let predicate = self.resolve_vars_if_possible(predicate.clone());
|
||||||
let mut pred_str = predicate.to_string();
|
let mut pred_str = predicate.to_string();
|
||||||
|
|
||||||
if pred_str.len() > 50 {
|
if pred_str.len() > 50 {
|
||||||
// We don't need to save the type to a file, we will be talking about this type already
|
// We don't need to save the type to a file, we will be talking about this type already
|
||||||
// in a separate note when we explain the obligation, so it will be available that way.
|
// in a separate note when we explain the obligation, so it will be available that way.
|
||||||
|
@ -483,7 +496,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
obligation.cause.span,
|
span,
|
||||||
E0275,
|
E0275,
|
||||||
"overflow evaluating the requirement `{}`",
|
"overflow evaluating the requirement `{}`",
|
||||||
pred_str,
|
pred_str,
|
||||||
|
@ -493,20 +506,46 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
self.suggest_new_overflow_limit(&mut err);
|
self.suggest_new_overflow_limit(&mut err);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.note_obligation_cause_code(
|
mutate(&mut err);
|
||||||
&mut err,
|
|
||||||
&obligation.predicate,
|
|
||||||
obligation.param_env,
|
|
||||||
obligation.cause.code(),
|
|
||||||
&mut vec![],
|
|
||||||
&mut Default::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
self.tcx.sess.abort_if_errors();
|
self.tcx.sess.abort_if_errors();
|
||||||
bug!();
|
bug!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reports that an overflow has occurred and halts compilation. We
|
||||||
|
/// halt compilation unconditionally because it is important that
|
||||||
|
/// overflows never be masked -- they basically represent computations
|
||||||
|
/// whose result could not be truly determined and thus we can't say
|
||||||
|
/// if the program type checks or not -- and they are unusual
|
||||||
|
/// occurrences in any case.
|
||||||
|
fn report_overflow_obligation<T>(
|
||||||
|
&self,
|
||||||
|
obligation: &Obligation<'tcx, T>,
|
||||||
|
suggest_increasing_limit: bool,
|
||||||
|
) -> !
|
||||||
|
where
|
||||||
|
T: ToPredicate<'tcx> + Clone,
|
||||||
|
{
|
||||||
|
let predicate = obligation.predicate.clone().to_predicate(self.tcx);
|
||||||
|
let predicate = self.resolve_vars_if_possible(predicate);
|
||||||
|
self.report_overflow_error(
|
||||||
|
&predicate,
|
||||||
|
obligation.cause.span,
|
||||||
|
suggest_increasing_limit,
|
||||||
|
|err| {
|
||||||
|
self.note_obligation_cause_code(
|
||||||
|
err,
|
||||||
|
&predicate,
|
||||||
|
obligation.param_env,
|
||||||
|
obligation.cause.code(),
|
||||||
|
&mut vec![],
|
||||||
|
&mut Default::default(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
|
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
|
||||||
let suggested_limit = match self.tcx.recursion_limit() {
|
let suggested_limit = match self.tcx.recursion_limit() {
|
||||||
Limit(0) => Limit(2),
|
Limit(0) => Limit(2),
|
||||||
|
@ -521,11 +560,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports that a cycle was detected which led to overflow and halts
|
/// Reports that a cycle was detected which led to overflow and halts
|
||||||
/// compilation. This is equivalent to `report_overflow_error` except
|
/// compilation. This is equivalent to `report_overflow_obligation` except
|
||||||
/// that we can give a more helpful error message (and, in particular,
|
/// that we can give a more helpful error message (and, in particular,
|
||||||
/// we do not suggest increasing the overflow limit, which is not
|
/// we do not suggest increasing the overflow limit, which is not
|
||||||
/// going to help).
|
/// going to help).
|
||||||
fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
|
fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
|
||||||
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
|
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
|
||||||
assert!(!cycle.is_empty());
|
assert!(!cycle.is_empty());
|
||||||
|
|
||||||
|
@ -533,7 +572,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
// The 'deepest' obligation is most likely to have a useful
|
// The 'deepest' obligation is most likely to have a useful
|
||||||
// cause 'backtrace'
|
// cause 'backtrace'
|
||||||
self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false);
|
self.report_overflow_obligation(
|
||||||
|
cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_selection_error(
|
fn report_selection_error(
|
||||||
|
@ -1554,7 +1596,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
diag.emit();
|
diag.emit();
|
||||||
}
|
}
|
||||||
FulfillmentErrorCode::CodeCycle(ref cycle) => {
|
FulfillmentErrorCode::CodeCycle(ref cycle) => {
|
||||||
self.report_overflow_error_cycle(cycle);
|
self.report_overflow_obligation_cycle(cycle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1607,7 +1649,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
| ObligationCauseCode::ObjectCastObligation(..)
|
| ObligationCauseCode::ObjectCastObligation(..)
|
||||||
| ObligationCauseCode::OpaqueType
|
| ObligationCauseCode::OpaqueType
|
||||||
);
|
);
|
||||||
let expected_ty = data.term.ty().unwrap();
|
let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error());
|
||||||
|
|
||||||
// constrain inference variables a bit more to nested obligations from normalize so
|
// constrain inference variables a bit more to nested obligations from normalize so
|
||||||
// we can have more helpful errors.
|
// we can have more helpful errors.
|
||||||
|
|
|
@ -298,7 +298,7 @@ pub trait TypeErrCtxtExt<'tcx> {
|
||||||
obligated_types: &mut Vec<Ty<'tcx>>,
|
obligated_types: &mut Vec<Ty<'tcx>>,
|
||||||
seen_requirements: &mut FxHashSet<DefId>,
|
seen_requirements: &mut FxHashSet<DefId>,
|
||||||
) where
|
) where
|
||||||
T: fmt::Display + ToPredicate<'tcx, T>;
|
T: fmt::Display + ToPredicate<'tcx>;
|
||||||
|
|
||||||
/// Suggest to await before try: future? => future.await?
|
/// Suggest to await before try: future? => future.await?
|
||||||
fn suggest_await_before_try(
|
fn suggest_await_before_try(
|
||||||
|
@ -2353,7 +2353,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
obligated_types: &mut Vec<Ty<'tcx>>,
|
obligated_types: &mut Vec<Ty<'tcx>>,
|
||||||
seen_requirements: &mut FxHashSet<DefId>,
|
seen_requirements: &mut FxHashSet<DefId>,
|
||||||
) where
|
) where
|
||||||
T: fmt::Display,
|
T: fmt::Display + ToPredicate<'tcx>,
|
||||||
{
|
{
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
match *cause_code {
|
match *cause_code {
|
||||||
|
|
|
@ -150,7 +150,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
|
||||||
fn pred_known_to_hold_modulo_regions<'tcx>(
|
fn pred_known_to_hold_modulo_regions<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
pred: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + TypeVisitable<'tcx>,
|
pred: impl ToPredicate<'tcx> + TypeVisitable<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let has_non_region_infer = pred.has_non_region_infer();
|
let has_non_region_infer = pred.has_non_region_infer();
|
||||||
|
|
|
@ -504,14 +504,12 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
Reveal::All => {
|
Reveal::All => {
|
||||||
let recursion_limit = self.tcx().recursion_limit();
|
let recursion_limit = self.tcx().recursion_limit();
|
||||||
if !recursion_limit.value_within_limit(self.depth) {
|
if !recursion_limit.value_within_limit(self.depth) {
|
||||||
let obligation = Obligation::with_depth(
|
self.selcx.infcx.err_ctxt().report_overflow_error(
|
||||||
self.tcx(),
|
&ty,
|
||||||
self.cause.clone(),
|
self.cause.span,
|
||||||
recursion_limit.0,
|
true,
|
||||||
self.param_env,
|
|_| {},
|
||||||
ty,
|
|
||||||
);
|
);
|
||||||
self.selcx.infcx.err_ctxt().report_overflow_error(&obligation, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let substs = substs.fold_with(self);
|
let substs = substs.fold_with(self);
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::infer::canonical::OriginalQueryValues;
|
||||||
use crate::infer::{InferCtxt, InferOk};
|
use crate::infer::{InferCtxt, InferOk};
|
||||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||||
use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
|
use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
|
||||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
|
use crate::traits::{ObligationCause, PredicateObligation, Reveal};
|
||||||
use rustc_data_structures::sso::SsoHashMap;
|
use rustc_data_structures::sso::SsoHashMap;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_infer::traits::Normalized;
|
use rustc_infer::traits::Normalized;
|
||||||
|
@ -214,14 +214,12 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||||
let substs = substs.try_fold_with(self)?;
|
let substs = substs.try_fold_with(self)?;
|
||||||
let recursion_limit = self.tcx().recursion_limit();
|
let recursion_limit = self.tcx().recursion_limit();
|
||||||
if !recursion_limit.value_within_limit(self.anon_depth) {
|
if !recursion_limit.value_within_limit(self.anon_depth) {
|
||||||
let obligation = Obligation::with_depth(
|
self.infcx.err_ctxt().report_overflow_error(
|
||||||
self.tcx(),
|
&ty,
|
||||||
self.cause.clone(),
|
self.cause.span,
|
||||||
recursion_limit.0,
|
true,
|
||||||
self.param_env,
|
|_| {},
|
||||||
ty,
|
|
||||||
);
|
);
|
||||||
self.infcx.err_ctxt().report_overflow_error(&obligation, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let generic_ty = self.tcx().bound_type_of(def_id);
|
let generic_ty = self.tcx().bound_type_of(def_id);
|
||||||
|
|
|
@ -43,7 +43,6 @@ use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||||
use rustc_middle::ty::fold::BottomUpFolder;
|
use rustc_middle::ty::fold::BottomUpFolder;
|
||||||
use rustc_middle::ty::print::{FmtPrinter, Print};
|
|
||||||
use rustc_middle::ty::relate::TypeRelation;
|
use rustc_middle::ty::relate::TypeRelation;
|
||||||
use rustc_middle::ty::SubstsRef;
|
use rustc_middle::ty::SubstsRef;
|
||||||
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||||
|
@ -1313,10 +1312,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
error_obligation: &Obligation<'tcx, T>,
|
error_obligation: &Obligation<'tcx, T>,
|
||||||
) -> Result<(), OverflowError>
|
) -> Result<(), OverflowError>
|
||||||
where
|
where
|
||||||
T: fmt::Display
|
T: ToPredicate<'tcx> + Clone,
|
||||||
+ TypeFoldable<'tcx>
|
|
||||||
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
|
||||||
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
|
|
||||||
{
|
{
|
||||||
if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
|
if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
|
||||||
match self.query_mode {
|
match self.query_mode {
|
||||||
|
@ -1324,7 +1320,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if let Some(e) = self.infcx.tainted_by_errors() {
|
if let Some(e) = self.infcx.tainted_by_errors() {
|
||||||
return Err(OverflowError::Error(e));
|
return Err(OverflowError::Error(e));
|
||||||
}
|
}
|
||||||
self.infcx.err_ctxt().report_overflow_error(error_obligation, true);
|
self.infcx.err_ctxt().report_overflow_obligation(error_obligation, true);
|
||||||
}
|
}
|
||||||
TraitQueryMode::Canonical => {
|
TraitQueryMode::Canonical => {
|
||||||
return Err(OverflowError::Canonical);
|
return Err(OverflowError::Canonical);
|
||||||
|
@ -1345,10 +1341,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
error_obligation: &Obligation<'tcx, V>,
|
error_obligation: &Obligation<'tcx, V>,
|
||||||
) -> Result<(), OverflowError>
|
) -> Result<(), OverflowError>
|
||||||
where
|
where
|
||||||
V: fmt::Display
|
V: ToPredicate<'tcx> + Clone,
|
||||||
+ TypeFoldable<'tcx>
|
|
||||||
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
|
||||||
<V as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
|
|
||||||
{
|
{
|
||||||
self.check_recursion_depth(obligation.recursion_depth, error_obligation)
|
self.check_recursion_depth(obligation.recursion_depth, error_obligation)
|
||||||
}
|
}
|
||||||
|
|
|
@ -476,9 +476,24 @@ impl<'tcx> WfPredicates<'tcx> {
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())),
|
ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// FIXME(generic_const_exprs): This seems wrong but I could not find a way to get this to trigger
|
|
||||||
ty::ConstKind::Expr(_) => {
|
ty::ConstKind::Expr(_) => {
|
||||||
bug!("checking wfness of `ConstKind::Expr` is unsupported")
|
// FIXME(generic_const_exprs): this doesnt verify that given `Expr(N + 1)` the
|
||||||
|
// trait bound `typeof(N): Add<typeof(1)>` holds. This is currently unnecessary
|
||||||
|
// as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated`
|
||||||
|
// which means that the `DefId` would have been typeck'd elsewhere. However in
|
||||||
|
// the future we may allow directly lowering to `ConstKind::Expr` in which case
|
||||||
|
// we would not be proving bounds we should.
|
||||||
|
|
||||||
|
let predicate =
|
||||||
|
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
|
||||||
|
let cause = self.cause(traits::WellFormed(None));
|
||||||
|
self.out.push(traits::Obligation::with_depth(
|
||||||
|
self.tcx(),
|
||||||
|
cause,
|
||||||
|
self.recursion_depth,
|
||||||
|
self.param_env,
|
||||||
|
predicate,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ConstKind::Error(_)
|
ty::ConstKind::Error(_)
|
||||||
|
|
|
@ -255,6 +255,16 @@ changelog-seen = 2
|
||||||
# Defaults to the Python interpreter used to execute x.py
|
# Defaults to the Python interpreter used to execute x.py
|
||||||
#python = "python"
|
#python = "python"
|
||||||
|
|
||||||
|
# The path to the REUSE executable to use. Note that REUSE is not required in
|
||||||
|
# most cases, as our tooling relies on a cached (and shrinked) copy of the
|
||||||
|
# REUSE output present in the git repository and in our source tarballs.
|
||||||
|
#
|
||||||
|
# REUSE is only needed if your changes caused the overral licensing of the
|
||||||
|
# repository to change, and the cached copy has to be regenerated.
|
||||||
|
#
|
||||||
|
# Defaults to the "reuse" command in the system path.
|
||||||
|
#reuse = "reuse"
|
||||||
|
|
||||||
# Force Cargo to check that Cargo.lock describes the precise dependency
|
# Force Cargo to check that Cargo.lock describes the precise dependency
|
||||||
# set that all the Cargo.toml files create, instead of updating it.
|
# set that all the Cargo.toml files create, instead of updating it.
|
||||||
#locked-deps = false
|
#locked-deps = false
|
||||||
|
|
|
@ -629,9 +629,7 @@ impl<T> Clone for Sender<T> {
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T> Drop for Sender<T> {
|
impl<T> Drop for Sender<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {}
|
||||||
let _ = self.inner;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "mpsc_debug", since = "1.8.0")]
|
#[stable(feature = "mpsc_debug", since = "1.8.0")]
|
||||||
|
@ -751,9 +749,7 @@ impl<T> Clone for SyncSender<T> {
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T> Drop for SyncSender<T> {
|
impl<T> Drop for SyncSender<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {}
|
||||||
let _ = self.inner;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "mpsc_debug", since = "1.8.0")]
|
#[stable(feature = "mpsc_debug", since = "1.8.0")]
|
||||||
|
@ -1094,9 +1090,7 @@ impl<T> IntoIterator for Receiver<T> {
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T> Drop for Receiver<T> {
|
impl<T> Drop for Receiver<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {}
|
||||||
let _ = self.inner;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "mpsc_debug", since = "1.8.0")]
|
#[stable(feature = "mpsc_debug", since = "1.8.0")]
|
||||||
|
|
|
@ -754,6 +754,8 @@ impl<'a> Builder<'a> {
|
||||||
run::BumpStage0,
|
run::BumpStage0,
|
||||||
run::ReplaceVersionPlaceholder,
|
run::ReplaceVersionPlaceholder,
|
||||||
run::Miri,
|
run::Miri,
|
||||||
|
run::CollectLicenseMetadata,
|
||||||
|
run::GenerateCopyright,
|
||||||
),
|
),
|
||||||
// These commands either don't use paths, or they're special-cased in Build::build()
|
// These commands either don't use paths, or they're special-cased in Build::build()
|
||||||
Kind::Clean | Kind::Format | Kind::Setup => vec![],
|
Kind::Clean | Kind::Format | Kind::Setup => vec![],
|
||||||
|
|
|
@ -213,6 +213,7 @@ pub struct Config {
|
||||||
pub npm: Option<PathBuf>,
|
pub npm: Option<PathBuf>,
|
||||||
pub gdb: Option<PathBuf>,
|
pub gdb: Option<PathBuf>,
|
||||||
pub python: Option<PathBuf>,
|
pub python: Option<PathBuf>,
|
||||||
|
pub reuse: Option<PathBuf>,
|
||||||
pub cargo_native_static: bool,
|
pub cargo_native_static: bool,
|
||||||
pub configure_args: Vec<String>,
|
pub configure_args: Vec<String>,
|
||||||
|
|
||||||
|
@ -611,6 +612,7 @@ define_config! {
|
||||||
nodejs: Option<String> = "nodejs",
|
nodejs: Option<String> = "nodejs",
|
||||||
npm: Option<String> = "npm",
|
npm: Option<String> = "npm",
|
||||||
python: Option<String> = "python",
|
python: Option<String> = "python",
|
||||||
|
reuse: Option<String> = "reuse",
|
||||||
locked_deps: Option<bool> = "locked-deps",
|
locked_deps: Option<bool> = "locked-deps",
|
||||||
vendor: Option<bool> = "vendor",
|
vendor: Option<bool> = "vendor",
|
||||||
full_bootstrap: Option<bool> = "full-bootstrap",
|
full_bootstrap: Option<bool> = "full-bootstrap",
|
||||||
|
@ -1004,6 +1006,7 @@ impl Config {
|
||||||
config.npm = build.npm.map(PathBuf::from);
|
config.npm = build.npm.map(PathBuf::from);
|
||||||
config.gdb = build.gdb.map(PathBuf::from);
|
config.gdb = build.gdb.map(PathBuf::from);
|
||||||
config.python = build.python.map(PathBuf::from);
|
config.python = build.python.map(PathBuf::from);
|
||||||
|
config.reuse = build.reuse.map(PathBuf::from);
|
||||||
config.submodules = build.submodules;
|
config.submodules = build.submodules;
|
||||||
set(&mut config.low_priority, build.low_priority);
|
set(&mut config.low_priority, build.low_priority);
|
||||||
set(&mut config.compiler_docs, build.compiler_docs);
|
set(&mut config.compiler_docs, build.compiler_docs);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
|
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
|
||||||
|
@ -189,3 +190,65 @@ impl Step for Miri {
|
||||||
builder.run(&mut miri);
|
builder.run(&mut miri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct CollectLicenseMetadata;
|
||||||
|
|
||||||
|
impl Step for CollectLicenseMetadata {
|
||||||
|
type Output = PathBuf;
|
||||||
|
const ONLY_HOSTS: bool = true;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.path("src/tools/collect-license-metadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
run.builder.ensure(CollectLicenseMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||||
|
let Some(reuse) = &builder.config.reuse else {
|
||||||
|
panic!("REUSE is required to collect the license metadata");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Temporary location, it will be moved to src/etc once it's accurate.
|
||||||
|
let dest = builder.out.join("license-metadata.json");
|
||||||
|
|
||||||
|
let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
|
||||||
|
cmd.env("REUSE_EXE", reuse);
|
||||||
|
cmd.env("DEST", &dest);
|
||||||
|
builder.run(&mut cmd);
|
||||||
|
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct GenerateCopyright;
|
||||||
|
|
||||||
|
impl Step for GenerateCopyright {
|
||||||
|
type Output = PathBuf;
|
||||||
|
const ONLY_HOSTS: bool = true;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.path("src/tools/generate-copyright")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
run.builder.ensure(GenerateCopyright);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||||
|
let license_metadata = builder.ensure(CollectLicenseMetadata);
|
||||||
|
|
||||||
|
// Temporary location, it will be moved to the proper one once it's accurate.
|
||||||
|
let dest = builder.out.join("COPYRIGHT.md");
|
||||||
|
|
||||||
|
let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
|
||||||
|
cmd.env("LICENSE_METADATA", &license_metadata);
|
||||||
|
cmd.env("DEST", &dest);
|
||||||
|
builder.run(&mut cmd);
|
||||||
|
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -140,6 +140,13 @@ than building it.
|
||||||
.map(|p| cmd_finder.must_have(p))
|
.map(|p| cmd_finder.must_have(p))
|
||||||
.or_else(|| cmd_finder.maybe_have("gdb"));
|
.or_else(|| cmd_finder.maybe_have("gdb"));
|
||||||
|
|
||||||
|
build.config.reuse = build
|
||||||
|
.config
|
||||||
|
.reuse
|
||||||
|
.take()
|
||||||
|
.map(|p| cmd_finder.must_have(p))
|
||||||
|
.or_else(|| cmd_finder.maybe_have("reuse"));
|
||||||
|
|
||||||
// We're gonna build some custom C code here and there, host triples
|
// We're gonna build some custom C code here and there, host triples
|
||||||
// also build some C++ shims for LLVM so we need a C++ compiler.
|
// also build some C++ shims for LLVM so we need a C++ compiler.
|
||||||
for target in &build.targets {
|
for target in &build.targets {
|
||||||
|
|
|
@ -380,6 +380,8 @@ bootstrap_tool!(
|
||||||
HtmlChecker, "src/tools/html-checker", "html-checker";
|
HtmlChecker, "src/tools/html-checker", "html-checker";
|
||||||
BumpStage0, "src/tools/bump-stage0", "bump-stage0";
|
BumpStage0, "src/tools/bump-stage0", "bump-stage0";
|
||||||
ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
|
ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
|
||||||
|
CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
|
||||||
|
GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
|
|
14
src/test/ui/async-await/in-trait/return-type-suggestion.rs
Normal file
14
src/test/ui/async-await/in-trait/return-type-suggestion.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
#![feature(async_fn_in_trait)]
|
||||||
|
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
|
||||||
|
trait A {
|
||||||
|
async fn e() {
|
||||||
|
Ok(())
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| HELP consider using a semicolon here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,23 @@
|
||||||
|
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/return-type-suggestion.rs:3:12
|
||||||
|
|
|
||||||
|
LL | #![feature(async_fn_in_trait)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/return-type-suggestion.rs:8:9
|
||||||
|
|
|
||||||
|
LL | Ok(())
|
||||||
|
| ^^^^^^- help: consider using a semicolon here: `;`
|
||||||
|
| |
|
||||||
|
| expected `()`, found enum `Result`
|
||||||
|
|
|
||||||
|
= note: expected unit type `()`
|
||||||
|
found enum `Result<(), _>`
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
11
src/test/ui/auto-traits/bad-generics-on-dyn.rs
Normal file
11
src/test/ui/auto-traits/bad-generics-on-dyn.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#![feature(auto_traits)]
|
||||||
|
|
||||||
|
auto trait Trait1<'a> {}
|
||||||
|
//~^ ERROR auto traits cannot have generic parameters
|
||||||
|
|
||||||
|
fn f<'a>(x: &dyn Trait1<'a>)
|
||||||
|
{}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
f(&1);
|
||||||
|
}
|
11
src/test/ui/auto-traits/bad-generics-on-dyn.stderr
Normal file
11
src/test/ui/auto-traits/bad-generics-on-dyn.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0567]: auto traits cannot have generic parameters
|
||||||
|
--> $DIR/bad-generics-on-dyn.rs:3:18
|
||||||
|
|
|
||||||
|
LL | auto trait Trait1<'a> {}
|
||||||
|
| ------^^^^ help: remove the parameters
|
||||||
|
| |
|
||||||
|
| auto trait cannot have generic parameters
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0567`.
|
|
@ -0,0 +1,22 @@
|
||||||
|
#![feature(generic_const_exprs, generic_arg_infer)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// minimized repro for #105205
|
||||||
|
//
|
||||||
|
// the `foo::<_, L>` call results in a `WellFormed(_)` obligation and a
|
||||||
|
// `ConstEvaluatable(Unevaluated(_ + 1 + L))` obligation. Attempting to fulfill the latter
|
||||||
|
// unifies the `_` with `Expr(L - 1)` from the paramenv which turns the `WellFormed`
|
||||||
|
// obligation into `WellFormed(Expr(L - 1))`
|
||||||
|
|
||||||
|
fn foo<const N: usize, const M: usize>(_: [(); N + 1 + M]) {}
|
||||||
|
|
||||||
|
fn ice<const L: usize>()
|
||||||
|
where
|
||||||
|
[(); (L - 1) + 1 + L]:,
|
||||||
|
{
|
||||||
|
foo::<_, L>([(); L + 1 + L]);
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
//~^^ ERROR: unconstrained generic constant
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,20 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/wf_obligation.rs:17:17
|
||||||
|
|
|
||||||
|
LL | foo::<_, L>([(); L + 1 + L]);
|
||||||
|
| ^^^^^^^^^^^^^^^ expected `N + 1 + M`, found `L + 1 + L`
|
||||||
|
|
|
||||||
|
= note: expected constant `N + 1 + M`
|
||||||
|
found constant `L + 1 + L`
|
||||||
|
|
||||||
|
error: unconstrained generic constant
|
||||||
|
--> $DIR/wf_obligation.rs:17:22
|
||||||
|
|
|
||||||
|
LL | foo::<_, L>([(); L + 1 + L]);
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
8
src/test/ui/impl-trait/nested-return-type4.rs
Normal file
8
src/test/ui/impl-trait/nested-return-type4.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
|
||||||
|
async move { let _s = s; }
|
||||||
|
//~^ ERROR hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
20
src/test/ui/impl-trait/nested-return-type4.stderr
Normal file
20
src/test/ui/impl-trait/nested-return-type4.stderr
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
|
||||||
|
--> $DIR/nested-return-type4.rs:4:5
|
||||||
|
|
|
||||||
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
|
||||||
|
| -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here
|
||||||
|
LL | async move { let _s = s; }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's {
|
||||||
|
| ++++
|
||||||
|
help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0700`.
|
21
src/test/ui/issues/issue-105330.rs
Normal file
21
src/test/ui/issues/issue-105330.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
pub trait TraitWAssocConst {
|
||||||
|
const A: usize;
|
||||||
|
}
|
||||||
|
pub struct Demo {}
|
||||||
|
|
||||||
|
impl TraitWAssocConst for impl Demo { //~ ERROR E0404
|
||||||
|
//~^ ERROR E0562
|
||||||
|
pubconst A: str = 32; //~ ERROR expected one of
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
|
||||||
|
foo::<Demo>()(); //~ ERROR E0271
|
||||||
|
//~^ ERROR E0618
|
||||||
|
//~| ERROR E0277
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131
|
||||||
|
//~^ ERROR E0658
|
||||||
|
foo::<Demo>(); //~ ERROR E0277
|
||||||
|
//~^ ERROR E0271
|
||||||
|
}
|
109
src/test/ui/issues/issue-105330.stderr
Normal file
109
src/test/ui/issues/issue-105330.stderr
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
error: expected one of `!` or `::`, found `A`
|
||||||
|
--> $DIR/issue-105330.rs:8:14
|
||||||
|
|
|
||||||
|
LL | impl TraitWAssocConst for impl Demo {
|
||||||
|
| - while parsing this item list starting here
|
||||||
|
LL |
|
||||||
|
LL | pubconst A: str = 32;
|
||||||
|
| ^ expected one of `!` or `::`
|
||||||
|
LL | }
|
||||||
|
| - the item list ends here
|
||||||
|
|
||||||
|
error[E0404]: expected trait, found struct `Demo`
|
||||||
|
--> $DIR/issue-105330.rs:6:32
|
||||||
|
|
|
||||||
|
LL | impl TraitWAssocConst for impl Demo {
|
||||||
|
| ^^^^ not a trait
|
||||||
|
|
||||||
|
error[E0658]: associated const equality is incomplete
|
||||||
|
--> $DIR/issue-105330.rs:11:28
|
||||||
|
|
|
||||||
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||||
|
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: associated const equality is incomplete
|
||||||
|
--> $DIR/issue-105330.rs:17:29
|
||||||
|
|
|
||||||
|
LL | fn main<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||||
|
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
|
||||||
|
--> $DIR/issue-105330.rs:6:27
|
||||||
|
|
|
||||||
|
LL | impl TraitWAssocConst for impl Demo {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
|
||||||
|
--> $DIR/issue-105330.rs:12:11
|
||||||
|
|
|
||||||
|
LL | foo::<Demo>()();
|
||||||
|
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/issue-105330.rs:11:11
|
||||||
|
|
|
||||||
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
|
||||||
|
--> $DIR/issue-105330.rs:12:11
|
||||||
|
|
|
||||||
|
LL | foo::<Demo>()();
|
||||||
|
| ^^^^ types differ
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/issue-105330.rs:11:28
|
||||||
|
|
|
||||||
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error[E0618]: expected function, found `()`
|
||||||
|
--> $DIR/issue-105330.rs:12:5
|
||||||
|
|
|
||||||
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ----------------------------------- `foo::<Demo>` defined here returns `()`
|
||||||
|
LL | foo::<Demo>()();
|
||||||
|
| ^^^^^^^^^^^^^--
|
||||||
|
| |
|
||||||
|
| call expression requires function
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
|
||||||
|
--> $DIR/issue-105330.rs:19:11
|
||||||
|
|
|
||||||
|
LL | foo::<Demo>();
|
||||||
|
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/issue-105330.rs:11:11
|
||||||
|
|
|
||||||
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
|
||||||
|
--> $DIR/issue-105330.rs:19:11
|
||||||
|
|
|
||||||
|
LL | foo::<Demo>();
|
||||||
|
| ^^^^ types differ
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/issue-105330.rs:11:28
|
||||||
|
|
|
||||||
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error[E0131]: `main` function is not allowed to have generic parameters
|
||||||
|
--> $DIR/issue-105330.rs:17:8
|
||||||
|
|
|
||||||
|
LL | fn main<A: TraitWAssocConst<A=32>>() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0131`.
|
|
@ -7,6 +7,7 @@ LL | $token $($inner)? = $value,
|
||||||
LL | values!(STRING(1) as (String) => cfg(test),);
|
LL | values!(STRING(1) as (String) => cfg(test),);
|
||||||
| -------------------------------------------- in this macro invocation
|
| -------------------------------------------- in this macro invocation
|
||||||
|
|
|
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
= note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: macro expansion ignores token `(String)` and any following
|
error: macro expansion ignores token `(String)` and any following
|
||||||
|
|
|
@ -3,6 +3,8 @@ error: unexpected `==`
|
||||||
|
|
|
|
||||||
LL | B == 2
|
LL | B == 2
|
||||||
| ^^ help: try using `=` instead
|
| ^^ help: try using `=` instead
|
||||||
|
|
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
|
|
||||||
error: expected item, found `==`
|
error: expected item, found `==`
|
||||||
--> $DIR/issue-101477-enum.rs:6:7
|
--> $DIR/issue-101477-enum.rs:6:7
|
||||||
|
|
9
src/test/ui/parser/issue-103869.rs
Normal file
9
src/test/ui/parser/issue-103869.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
enum VecOrMap{
|
||||||
|
vec: Vec<usize>,
|
||||||
|
//~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `:`
|
||||||
|
//~| HELP: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
|
//~| ERROR expected item, found `:`
|
||||||
|
map: HashMap<String,usize>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
16
src/test/ui/parser/issue-103869.stderr
Normal file
16
src/test/ui/parser/issue-103869.stderr
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `:`
|
||||||
|
--> $DIR/issue-103869.rs:2:8
|
||||||
|
|
|
||||||
|
LL | vec: Vec<usize>,
|
||||||
|
| ^ expected one of `(`, `,`, `=`, `{`, or `}`
|
||||||
|
|
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
|
|
||||||
|
error: expected item, found `:`
|
||||||
|
--> $DIR/issue-103869.rs:2:8
|
||||||
|
|
|
||||||
|
LL | vec: Vec<usize>,
|
||||||
|
| ^ expected item
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -9,6 +9,7 @@ LL | $( $t, )*
|
||||||
LL | test_macro!(String,);
|
LL | test_macro!(String,);
|
||||||
| -------------------- in this macro invocation
|
| -------------------- in this macro invocation
|
||||||
|
|
|
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
= note: this error originates in the macro `test_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `test_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum E {
|
||||||
//~^ ERROR functions are not allowed in enum definitions
|
//~^ ERROR functions are not allowed in enum definitions
|
||||||
//~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks
|
//~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks
|
||||||
//~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
|
//~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
|
||||||
|
//~| HELP enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -33,6 +33,7 @@ LL | fn foo() {}
|
||||||
|
|
|
|
||||||
= help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
|
= help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
|
||||||
= help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
|
= help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
trait Trait<T> {
|
||||||
|
fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait<()> for () {
|
||||||
|
fn foo<'a, K>(self, _: (), _: K) where { //~ ERROR E0195
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct State;
|
||||||
|
|
||||||
|
trait Foo<T> {
|
||||||
|
fn foo<'a>(&self, state: &'a State) -> &'a T
|
||||||
|
where
|
||||||
|
T: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T> Foo<T> for F
|
||||||
|
where
|
||||||
|
F: Fn(&State) -> &T,
|
||||||
|
{
|
||||||
|
fn foo<'a>(&self, state: &'a State) -> &'a T { //~ ERROR E0195
|
||||||
|
self(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Bar {
|
||||||
|
fn foo<'a>(&'a self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bar for () {
|
||||||
|
fn foo<'a: 'a>(&'a self) {} //~ ERROR E0195
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
().foo((), ());
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
|
||||||
|
--> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:6:11
|
||||||
|
|
|
||||||
|
LL | fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a;
|
||||||
|
| ------- -- -- this bound might be missing in the impl
|
||||||
|
| | |
|
||||||
|
| | this bound might be missing in the impl
|
||||||
|
| lifetimes in impl do not match this method in trait
|
||||||
|
...
|
||||||
|
LL | fn foo<'a, K>(self, _: (), _: K) where {
|
||||||
|
| ^^^^^^^ lifetimes do not match method in trait
|
||||||
|
|
||||||
|
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
|
||||||
|
--> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:23:11
|
||||||
|
|
|
||||||
|
LL | fn foo<'a>(&self, state: &'a State) -> &'a T
|
||||||
|
| ---- lifetimes in impl do not match this method in trait
|
||||||
|
LL | where
|
||||||
|
LL | T: 'a;
|
||||||
|
| -- this bound might be missing in the impl
|
||||||
|
...
|
||||||
|
LL | fn foo<'a>(&self, state: &'a State) -> &'a T {
|
||||||
|
| ^^^^ lifetimes do not match method in trait
|
||||||
|
|
||||||
|
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
|
||||||
|
--> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:33:11
|
||||||
|
|
|
||||||
|
LL | fn foo<'a>(&'a self) {}
|
||||||
|
| ---- lifetimes in impl do not match this method in trait
|
||||||
|
...
|
||||||
|
LL | fn foo<'a: 'a>(&'a self) {}
|
||||||
|
| ^^^^^^^^ lifetimes do not match method in trait
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0195`.
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
let page_size = page_size::get();
|
||||||
|
//~^ ERROR failed to resolve: use of undeclared crate or module `page_size`
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0433]: failed to resolve: use of undeclared crate or module `page_size`
|
||||||
|
--> $DIR/path-to-method-sugg-unresolved-expr.rs:2:21
|
||||||
|
|
|
||||||
|
LL | let page_size = page_size::get();
|
||||||
|
| ^^^^^^^^^ use of undeclared crate or module `page_size`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0433`.
|
10
src/tools/collect-license-metadata/Cargo.toml
Normal file
10
src/tools/collect-license-metadata/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "collect-license-metadata"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.65"
|
||||||
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
|
serde_json = "1.0.85"
|
||||||
|
spdx-rs = "0.5.1"
|
65
src/tools/collect-license-metadata/src/licenses.rs
Normal file
65
src/tools/collect-license-metadata/src/licenses.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
const COPYRIGHT_PREFIXES: &[&str] = &["SPDX-FileCopyrightText:", "Copyright", "(c)", "(C)", "©"];
|
||||||
|
|
||||||
|
pub(crate) struct LicensesInterner {
|
||||||
|
by_id: Vec<License>,
|
||||||
|
by_struct: HashMap<License, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LicensesInterner {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
LicensesInterner { by_id: Vec::new(), by_struct: HashMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn intern(&mut self, mut license: License) -> LicenseId {
|
||||||
|
license.simplify();
|
||||||
|
if let Some(id) = self.by_struct.get(&license) {
|
||||||
|
LicenseId(*id)
|
||||||
|
} else {
|
||||||
|
let id = self.by_id.len();
|
||||||
|
self.by_id.push(license.clone());
|
||||||
|
self.by_struct.insert(license, id);
|
||||||
|
LicenseId(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve(&self, id: LicenseId) -> &License {
|
||||||
|
&self.by_id[id.0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub(crate) struct LicenseId(usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, PartialEq, Eq, serde::Serialize)]
|
||||||
|
pub(crate) struct License {
|
||||||
|
pub(crate) spdx: String,
|
||||||
|
pub(crate) copyright: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl License {
|
||||||
|
fn simplify(&mut self) {
|
||||||
|
self.remove_copyright_prefixes();
|
||||||
|
self.copyright.sort();
|
||||||
|
self.copyright.dedup();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_copyright_prefixes(&mut self) {
|
||||||
|
for copyright in &mut self.copyright {
|
||||||
|
let mut stripped = copyright.trim();
|
||||||
|
let mut previous_stripped;
|
||||||
|
loop {
|
||||||
|
previous_stripped = stripped;
|
||||||
|
for pattern in COPYRIGHT_PREFIXES {
|
||||||
|
stripped = stripped.trim_start_matches(pattern).trim_start();
|
||||||
|
}
|
||||||
|
if stripped == previous_stripped {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*copyright = stripped.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
src/tools/collect-license-metadata/src/main.rs
Normal file
30
src/tools/collect-license-metadata/src/main.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
mod licenses;
|
||||||
|
mod path_tree;
|
||||||
|
mod reuse;
|
||||||
|
|
||||||
|
use crate::licenses::LicensesInterner;
|
||||||
|
use anyhow::Error;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into();
|
||||||
|
let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into();
|
||||||
|
|
||||||
|
let mut interner = LicensesInterner::new();
|
||||||
|
let paths = crate::reuse::collect(&reuse_exe, &mut interner)?;
|
||||||
|
|
||||||
|
let mut tree = crate::path_tree::build(paths);
|
||||||
|
tree.simplify();
|
||||||
|
|
||||||
|
if let Some(parent) = dest.parent() {
|
||||||
|
std::fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
std::fs::write(
|
||||||
|
&dest,
|
||||||
|
&serde_json::to_vec_pretty(&serde_json::json!({
|
||||||
|
"files": crate::path_tree::expand_interned_licenses(tree, &interner),
|
||||||
|
}))?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
294
src/tools/collect-license-metadata/src/path_tree.rs
Normal file
294
src/tools/collect-license-metadata/src/path_tree.rs
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
//! Tools like REUSE output per-file licensing information, but we need to condense it in the
|
||||||
|
//! minimum amount of data that still represents the same licensing metadata. This module is
|
||||||
|
//! responsible for that, by turning the list of paths into a tree and executing simplification
|
||||||
|
//! passes over the tree to remove redundant information.
|
||||||
|
|
||||||
|
use crate::licenses::{License, LicenseId, LicensesInterner};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
#[serde(rename_all = "kebab-case", tag = "type")]
|
||||||
|
pub(crate) enum Node<L> {
|
||||||
|
Root { childs: Vec<Node<L>> },
|
||||||
|
Directory { name: PathBuf, childs: Vec<Node<L>>, license: Option<L> },
|
||||||
|
File { name: PathBuf, license: L },
|
||||||
|
FileGroup { names: Vec<PathBuf>, license: L },
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<LicenseId> {
|
||||||
|
pub(crate) fn simplify(&mut self) {
|
||||||
|
self.merge_directories();
|
||||||
|
self.collapse_in_licensed_directories();
|
||||||
|
self.merge_directory_licenses();
|
||||||
|
self.merge_file_groups();
|
||||||
|
self.remove_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initially, the build() function constructs a list of separate paths from the file
|
||||||
|
/// system root down to each file, like so:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// ┌─► ./ ──► compiler/ ──► rustc/ ──► src/ ──► main.rs
|
||||||
|
/// │
|
||||||
|
/// <root> ─┼─► ./ ──► compiler/ ──► rustc/ ──► Cargo.toml
|
||||||
|
/// │
|
||||||
|
/// └─► ./ ──► library/ ───► std/ ──► Cargo.toml
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This pass is responsible for turning that into a proper directory tree:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// ┌─► compiler/ ──► rustc/ ──┬─► src/ ──► main.rs
|
||||||
|
/// │ │
|
||||||
|
/// <root> ──► ./ ──┤ └─► Cargo.toml
|
||||||
|
/// │
|
||||||
|
/// └─► library/ ───► std/ ──► Cargo.toml
|
||||||
|
/// ```
|
||||||
|
fn merge_directories(&mut self) {
|
||||||
|
match self {
|
||||||
|
Node::Root { childs } | Node::Directory { childs, license: None, .. } => {
|
||||||
|
let mut directories = BTreeMap::new();
|
||||||
|
let mut files = Vec::new();
|
||||||
|
|
||||||
|
for child in childs.drain(..) {
|
||||||
|
match child {
|
||||||
|
Node::Directory { name, mut childs, license: None } => {
|
||||||
|
directories.entry(name).or_insert_with(Vec::new).append(&mut childs);
|
||||||
|
}
|
||||||
|
file @ Node::File { .. } => {
|
||||||
|
files.push(file);
|
||||||
|
}
|
||||||
|
Node::Empty => {}
|
||||||
|
Node::Root { .. } => {
|
||||||
|
panic!("can't have a root inside another element");
|
||||||
|
}
|
||||||
|
Node::FileGroup { .. } => {
|
||||||
|
panic!("FileGroup should not be present at this stage");
|
||||||
|
}
|
||||||
|
Node::Directory { license: Some(_), .. } => {
|
||||||
|
panic!("license should not be set at this stage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
childs.extend(directories.into_iter().map(|(name, childs)| Node::Directory {
|
||||||
|
name,
|
||||||
|
childs,
|
||||||
|
license: None,
|
||||||
|
}));
|
||||||
|
childs.append(&mut files);
|
||||||
|
|
||||||
|
for child in &mut *childs {
|
||||||
|
child.merge_directories();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::Empty => {}
|
||||||
|
Node::File { .. } => {}
|
||||||
|
Node::FileGroup { .. } => {
|
||||||
|
panic!("FileGroup should not be present at this stage");
|
||||||
|
}
|
||||||
|
Node::Directory { license: Some(_), .. } => {
|
||||||
|
panic!("license should not be set at this stage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// In our codebase, most files in a directory have the same license as the other files in that
|
||||||
|
/// same directory, so it's redundant to store licensing metadata for all the files. Instead,
|
||||||
|
/// we can add a license for a whole directory, and only record the exceptions to a directory
|
||||||
|
/// licensing metadata.
|
||||||
|
///
|
||||||
|
/// We cannot instead record only the difference to Rust's standard licensing, as the majority
|
||||||
|
/// of the files in our repository are *not* licensed under Rust's standard licensing due to
|
||||||
|
/// our inclusion of LLVM.
|
||||||
|
fn collapse_in_licensed_directories(&mut self) {
|
||||||
|
match self {
|
||||||
|
Node::Directory { childs, license, .. } => {
|
||||||
|
for child in &mut *childs {
|
||||||
|
child.collapse_in_licensed_directories();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut licenses_count = BTreeMap::new();
|
||||||
|
for child in &*childs {
|
||||||
|
let Some(license) = child.license() else { continue };
|
||||||
|
*licenses_count.entry(license).or_insert(0) += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let most_popular_license = licenses_count
|
||||||
|
.into_iter()
|
||||||
|
.max_by_key(|(_, count)| *count)
|
||||||
|
.map(|(license, _)| license);
|
||||||
|
|
||||||
|
if let Some(most_popular_license) = most_popular_license {
|
||||||
|
childs.retain(|child| child.license() != Some(most_popular_license));
|
||||||
|
*license = Some(most_popular_license);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::Root { childs } => {
|
||||||
|
for child in &mut *childs {
|
||||||
|
child.collapse_in_licensed_directories();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::File { .. } => {}
|
||||||
|
Node::FileGroup { .. } => {}
|
||||||
|
Node::Empty => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reduce the depth of the tree by merging subdirectories with the same license as their
|
||||||
|
/// parent directory into their parent, and adjusting the paths of the childs accordingly.
|
||||||
|
fn merge_directory_licenses(&mut self) {
|
||||||
|
match self {
|
||||||
|
Node::Root { childs } => {
|
||||||
|
for child in &mut *childs {
|
||||||
|
child.merge_directory_licenses();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::Directory { childs, license, .. } => {
|
||||||
|
let mut to_add = Vec::new();
|
||||||
|
for child in &mut *childs {
|
||||||
|
child.merge_directory_licenses();
|
||||||
|
|
||||||
|
let Node::Directory {
|
||||||
|
name: child_name,
|
||||||
|
childs: child_childs,
|
||||||
|
license: child_license,
|
||||||
|
} = child else { continue };
|
||||||
|
|
||||||
|
if child_license != license {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for mut child_child in child_childs.drain(..) {
|
||||||
|
match &mut child_child {
|
||||||
|
Node::Root { .. } => {
|
||||||
|
panic!("can't have a root inside another element");
|
||||||
|
}
|
||||||
|
Node::FileGroup { .. } => {
|
||||||
|
panic!("FileGroup should not be present at this stage");
|
||||||
|
}
|
||||||
|
Node::Directory { name: child_child_name, .. } => {
|
||||||
|
*child_child_name = child_name.join(&child_child_name);
|
||||||
|
}
|
||||||
|
Node::File { name: child_child_name, .. } => {
|
||||||
|
*child_child_name = child_name.join(&child_child_name);
|
||||||
|
}
|
||||||
|
Node::Empty => {}
|
||||||
|
}
|
||||||
|
to_add.push(child_child);
|
||||||
|
}
|
||||||
|
|
||||||
|
*child = Node::Empty;
|
||||||
|
}
|
||||||
|
childs.append(&mut to_add);
|
||||||
|
}
|
||||||
|
Node::Empty => {}
|
||||||
|
Node::File { .. } => {}
|
||||||
|
Node::FileGroup { .. } => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This pass groups multiple files in a directory with the same license into a single
|
||||||
|
/// "FileGroup", so that the license of all those files can be reported as a group.
|
||||||
|
///
|
||||||
|
/// Crucially this pass runs after collapse_in_licensed_directories, so the most common license
|
||||||
|
/// will already be marked as the directory's license and won't be turned into a group.
|
||||||
|
fn merge_file_groups(&mut self) {
|
||||||
|
match self {
|
||||||
|
Node::Root { childs } | Node::Directory { childs, .. } => {
|
||||||
|
let mut grouped = BTreeMap::new();
|
||||||
|
|
||||||
|
for child in &mut *childs {
|
||||||
|
child.merge_file_groups();
|
||||||
|
if let Node::File { name, license } = child {
|
||||||
|
grouped.entry(*license).or_insert_with(Vec::new).push(name.clone());
|
||||||
|
*child = Node::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (license, mut names) in grouped.into_iter() {
|
||||||
|
if names.len() == 1 {
|
||||||
|
childs.push(Node::File { license, name: names.pop().unwrap() });
|
||||||
|
} else {
|
||||||
|
childs.push(Node::FileGroup { license, names });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::File { .. } => {}
|
||||||
|
Node::FileGroup { .. } => panic!("FileGroup should not be present at this stage"),
|
||||||
|
Node::Empty => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Some nodes were replaced with Node::Empty to mark them for deletion. As the last step, make
|
||||||
|
/// sure to remove them from the tree.
|
||||||
|
fn remove_empty(&mut self) {
|
||||||
|
match self {
|
||||||
|
Node::Root { childs } | Node::Directory { childs, .. } => {
|
||||||
|
for child in &mut *childs {
|
||||||
|
child.remove_empty();
|
||||||
|
}
|
||||||
|
childs.retain(|child| !matches!(child, Node::Empty));
|
||||||
|
}
|
||||||
|
Node::FileGroup { .. } => {}
|
||||||
|
Node::File { .. } => {}
|
||||||
|
Node::Empty => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn license(&self) -> Option<LicenseId> {
|
||||||
|
match self {
|
||||||
|
Node::Directory { childs, license: Some(license), .. } if childs.is_empty() => {
|
||||||
|
Some(*license)
|
||||||
|
}
|
||||||
|
Node::File { license, .. } => Some(*license),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
|
||||||
|
let mut childs = Vec::new();
|
||||||
|
|
||||||
|
// Ensure reproducibility of all future steps.
|
||||||
|
input.sort();
|
||||||
|
|
||||||
|
for (path, license) in input {
|
||||||
|
let mut node = Node::File { name: path.file_name().unwrap().into(), license };
|
||||||
|
for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() {
|
||||||
|
node = Node::Directory {
|
||||||
|
name: component.as_os_str().into(),
|
||||||
|
childs: vec![node],
|
||||||
|
license: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
childs.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node::Root { childs }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a `Node<LicenseId>` into a `Node<&License>`, expanding all interned license IDs with a
|
||||||
|
/// reference to the actual license metadata.
|
||||||
|
pub(crate) fn expand_interned_licenses(
|
||||||
|
node: Node<LicenseId>,
|
||||||
|
interner: &LicensesInterner,
|
||||||
|
) -> Node<&License> {
|
||||||
|
match node {
|
||||||
|
Node::Root { childs } => Node::Root {
|
||||||
|
childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(),
|
||||||
|
},
|
||||||
|
Node::Directory { name, childs, license } => Node::Directory {
|
||||||
|
childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(),
|
||||||
|
license: license.map(|license| interner.resolve(license)),
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
Node::File { name, license } => Node::File { name, license: interner.resolve(license) },
|
||||||
|
Node::FileGroup { names, license } => {
|
||||||
|
Node::FileGroup { names, license: interner.resolve(license) }
|
||||||
|
}
|
||||||
|
Node::Empty => Node::Empty,
|
||||||
|
}
|
||||||
|
}
|
49
src/tools/collect-license-metadata/src/reuse.rs
Normal file
49
src/tools/collect-license-metadata/src/reuse.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use crate::licenses::{License, LicenseId, LicensesInterner};
|
||||||
|
use anyhow::Error;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
pub(crate) fn collect(
|
||||||
|
reuse_exe: &Path,
|
||||||
|
interner: &mut LicensesInterner,
|
||||||
|
) -> Result<Vec<(PathBuf, LicenseId)>, Error> {
|
||||||
|
eprintln!("gathering license information from REUSE");
|
||||||
|
let start = Instant::now();
|
||||||
|
let raw = &obtain_spdx_document(reuse_exe)?;
|
||||||
|
eprintln!("finished gathering the license information from REUSE in {:.2?}", start.elapsed());
|
||||||
|
|
||||||
|
let document = spdx_rs::parsers::spdx_from_tag_value(&raw)?;
|
||||||
|
|
||||||
|
let mut result = Vec::new();
|
||||||
|
for file in document.file_information {
|
||||||
|
let license = interner.intern(License {
|
||||||
|
spdx: file.concluded_license.to_string(),
|
||||||
|
copyright: file.copyright_text.split('\n').map(|s| s.into()).collect(),
|
||||||
|
});
|
||||||
|
|
||||||
|
result.push((file.file_name.into(), license));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn obtain_spdx_document(reuse_exe: &Path) -> Result<String, Error> {
|
||||||
|
let output = Command::new(reuse_exe)
|
||||||
|
.args(&["spdx", "--add-license-concluded", "--creator-person=bors"])
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()?
|
||||||
|
.wait_with_output()?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!();
|
||||||
|
eprintln!("Note that Rust requires some REUSE features that might not be present in the");
|
||||||
|
eprintln!("release you're using. Make sure your REUSE release includes these PRs:");
|
||||||
|
eprintln!();
|
||||||
|
eprintln!(" - https://github.com/fsfe/reuse-tool/pull/623");
|
||||||
|
eprintln!();
|
||||||
|
anyhow::bail!("collecting licensing information with REUSE failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(String::from_utf8(output.stdout)?)
|
||||||
|
}
|
11
src/tools/generate-copyright/Cargo.toml
Normal file
11
src/tools/generate-copyright/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "generate-copyright"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.65"
|
||||||
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
|
serde_json = "1.0.85"
|
94
src/tools/generate-copyright/src/main.rs
Normal file
94
src/tools/generate-copyright/src/main.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use anyhow::Error;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let dest = env_path("DEST")?;
|
||||||
|
let license_metadata = env_path("LICENSE_METADATA")?;
|
||||||
|
|
||||||
|
let metadata: Metadata = serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
|
||||||
|
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
render_recursive(&metadata.files, &mut buffer, 0)?;
|
||||||
|
|
||||||
|
std::fs::write(&dest, &buffer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(), Error> {
|
||||||
|
let prefix = std::iter::repeat("> ").take(depth + 1).collect::<String>();
|
||||||
|
|
||||||
|
match node {
|
||||||
|
Node::Root { childs } => {
|
||||||
|
for child in childs {
|
||||||
|
render_recursive(child, buffer, depth)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::Directory { name, childs, license } => {
|
||||||
|
render_license(&prefix, std::iter::once(name), license, buffer)?;
|
||||||
|
if !childs.is_empty() {
|
||||||
|
writeln!(buffer, "{prefix}")?;
|
||||||
|
writeln!(buffer, "{prefix}*Exceptions:*")?;
|
||||||
|
for child in childs {
|
||||||
|
writeln!(buffer, "{prefix}")?;
|
||||||
|
render_recursive(child, buffer, depth + 1)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::FileGroup { names, license } => {
|
||||||
|
render_license(&prefix, names.iter(), license, buffer)?;
|
||||||
|
}
|
||||||
|
Node::File { name, license } => {
|
||||||
|
render_license(&prefix, std::iter::once(name), license, buffer)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_license<'a>(
|
||||||
|
prefix: &str,
|
||||||
|
names: impl Iterator<Item = &'a String>,
|
||||||
|
license: &License,
|
||||||
|
buffer: &mut Vec<u8>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
for name in names {
|
||||||
|
writeln!(buffer, "{prefix}**`{name}`** ")?;
|
||||||
|
}
|
||||||
|
writeln!(buffer, "{prefix}License: `{}` ", license.spdx)?;
|
||||||
|
for (i, copyright) in license.copyright.iter().enumerate() {
|
||||||
|
let suffix = if i == license.copyright.len() - 1 { "" } else { " " };
|
||||||
|
writeln!(buffer, "{prefix}Copyright: {copyright}{suffix}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct Metadata {
|
||||||
|
files: Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case", tag = "type")]
|
||||||
|
pub(crate) enum Node {
|
||||||
|
Root { childs: Vec<Node> },
|
||||||
|
Directory { name: String, childs: Vec<Node>, license: License },
|
||||||
|
File { name: String, license: License },
|
||||||
|
FileGroup { names: Vec<String>, license: License },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct License {
|
||||||
|
spdx: String,
|
||||||
|
copyright: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env_path(var: &str) -> Result<PathBuf, Error> {
|
||||||
|
if let Some(var) = std::env::var_os(var) {
|
||||||
|
Ok(var.into())
|
||||||
|
} else {
|
||||||
|
anyhow::bail!("missing environment variable {var}")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue