Auto merge of #109714 - matthiaskrgr:rollup-wipns5h, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #109149 (Improve error message when writer is forgotten in write and writeln macro)
 - #109367 (Streamline fast rejection)
 - #109548 (AnnotationColumn struct to fix hard tab column numbers in errors)
 - #109694 (do not panic on failure to acquire jobserver token)
 - #109705 (new solver: check for intercrate mode when accessing the cache)
 - #109708 (Specialization involving RPITITs is broken so ignore the diagnostic differences)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-29 04:23:06 +00:00
commit 40cd0310db
23 changed files with 345 additions and 102 deletions

View File

@ -1452,8 +1452,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
Err(e) => {
let msg = &format!("failed to acquire jobserver token: {}", e);
shared_emitter.fatal(msg);
// Exit the coordinator thread
panic!("{}", msg)
codegen_done = true;
codegen_aborted = true;
}
}
}

View File

@ -202,7 +202,10 @@ impl AnnotateSnippetEmitterWriter {
annotations: annotations
.iter()
.map(|annotation| SourceAnnotation {
range: (annotation.start_col, annotation.end_col),
range: (
annotation.start_col.display,
annotation.end_col.display,
),
label: annotation.label.as_deref().unwrap_or_default(),
annotation_type: annotation_type_for_level(*level),
})

View File

@ -12,7 +12,9 @@ use Destination::*;
use rustc_span::source_map::SourceMap;
use rustc_span::{FileLines, SourceFile, Span};
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::snippet::{
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
};
use crate::styled_buffer::StyledBuffer;
use crate::translation::{to_fluent_args, Translate};
use crate::{
@ -858,7 +860,7 @@ impl EmitterWriter {
let mut short_start = true;
for ann in &line.annotations {
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) {
let style = if ann.is_primary {
Style::UnderlinePrimary
} else {
@ -1093,15 +1095,15 @@ impl EmitterWriter {
'_',
line_offset + pos,
width_offset + depth,
(code_offset + annotation.start_col).saturating_sub(left),
(code_offset + annotation.start_col.display).saturating_sub(left),
style,
);
}
_ if self.teach => {
buffer.set_style_range(
line_offset,
(code_offset + annotation.start_col).saturating_sub(left),
(code_offset + annotation.end_col).saturating_sub(left),
(code_offset + annotation.start_col.display).saturating_sub(left),
(code_offset + annotation.end_col.display).saturating_sub(left),
style,
annotation.is_primary,
);
@ -1133,7 +1135,7 @@ impl EmitterWriter {
for p in line_offset + 1..=line_offset + pos {
buffer.putc(
p,
(code_offset + annotation.start_col).saturating_sub(left),
(code_offset + annotation.start_col.display).saturating_sub(left),
'|',
style,
);
@ -1169,9 +1171,9 @@ impl EmitterWriter {
let style =
if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary };
let (pos, col) = if pos == 0 {
(pos + 1, (annotation.end_col + 1).saturating_sub(left))
(pos + 1, (annotation.end_col.display + 1).saturating_sub(left))
} else {
(pos + 2, annotation.start_col.saturating_sub(left))
(pos + 2, annotation.start_col.display.saturating_sub(left))
};
if let Some(ref label) = annotation.label {
buffer.puts(line_offset + pos, code_offset + col, label, style);
@ -1208,7 +1210,7 @@ impl EmitterWriter {
} else {
('-', Style::UnderlineSecondary)
};
for p in annotation.start_col..annotation.end_col {
for p in annotation.start_col.display..annotation.end_col.display {
buffer.putc(
line_offset + 1,
(code_offset + p).saturating_sub(left),
@ -1459,7 +1461,7 @@ impl EmitterWriter {
&annotated_file.file.name,
line.line_index
),
annotations[0].start_col + 1,
annotations[0].start_col.file + 1,
),
Style::LineAndColumn,
);
@ -1546,7 +1548,7 @@ impl EmitterWriter {
buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
let loc = if let Some(first_line) = annotated_file.lines.first() {
let col = if let Some(first_annotation) = first_line.annotations.first() {
format!(":{}", first_annotation.start_col + 1)
format!(":{}", first_annotation.start_col.file + 1)
} else {
String::new()
};
@ -1607,8 +1609,8 @@ impl EmitterWriter {
let mut span_left_margin = usize::MAX;
for line in &annotated_file.lines {
for ann in &line.annotations {
span_left_margin = min(span_left_margin, ann.start_col);
span_left_margin = min(span_left_margin, ann.end_col);
span_left_margin = min(span_left_margin, ann.start_col.display);
span_left_margin = min(span_left_margin, ann.end_col.display);
}
}
if span_left_margin == usize::MAX {
@ -1625,11 +1627,12 @@ impl EmitterWriter {
annotated_file.file.get_line(line.line_index - 1).map_or(0, |s| s.len()),
);
for ann in &line.annotations {
span_right_margin = max(span_right_margin, ann.start_col);
span_right_margin = max(span_right_margin, ann.end_col);
span_right_margin = max(span_right_margin, ann.start_col.display);
span_right_margin = max(span_right_margin, ann.end_col.display);
// FIXME: account for labels not in the same line
let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1);
label_right_margin = max(label_right_margin, ann.end_col + label_right);
label_right_margin =
max(label_right_margin, ann.end_col.display + label_right);
}
}
@ -2352,8 +2355,8 @@ impl FileWithAnnotatedLines {
depth: 1,
line_start: lo.line,
line_end: hi.line,
start_col: lo.col_display,
end_col: hi.col_display,
start_col: AnnotationColumn::from_loc(&lo),
end_col: AnnotationColumn::from_loc(&hi),
is_primary,
label,
overlaps_exactly: false,
@ -2361,8 +2364,8 @@ impl FileWithAnnotatedLines {
multiline_annotations.push((lo.file, ml));
} else {
let ann = Annotation {
start_col: lo.col_display,
end_col: hi.col_display,
start_col: AnnotationColumn::from_loc(&lo),
end_col: AnnotationColumn::from_loc(&hi),
is_primary,
label,
annotation_type: AnnotationType::Singleline,
@ -2551,7 +2554,13 @@ fn num_overlap(
(b_start..b_end + extra).contains(&a_start) || (a_start..a_end + extra).contains(&b_start)
}
fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false)
num_overlap(
a1.start_col.display,
a1.end_col.display + padding,
a2.start_col.display,
a2.end_col.display,
false,
)
}
fn emit_to_destination(

View File

@ -1,6 +1,6 @@
// Code for annotating snippets.
use crate::Level;
use crate::{Level, Loc};
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line {
@ -8,13 +8,39 @@ pub struct Line {
pub annotations: Vec<Annotation>,
}
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)]
pub struct AnnotationColumn {
/// the (0-indexed) column for *display* purposes, counted in characters, not utf-8 bytes
pub display: usize,
/// the (0-indexed) column in the file, counted in characters, not utf-8 bytes.
///
/// this may be different from `self.display`,
/// e.g. if the file contains hard tabs, because we convert tabs to spaces for error messages.
///
/// for example:
/// ```text
/// (hard tab)hello
/// ^ this is display column 4, but file column 1
/// ```
///
/// we want to keep around the correct file offset so that column numbers in error messages
/// are correct. (motivated by <https://github.com/rust-lang/rust/issues/109537>)
pub file: usize,
}
impl AnnotationColumn {
pub fn from_loc(loc: &Loc) -> AnnotationColumn {
AnnotationColumn { display: loc.col_display, file: loc.col.0 }
}
}
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct MultilineAnnotation {
pub depth: usize,
pub line_start: usize,
pub line_end: usize,
pub start_col: usize,
pub end_col: usize,
pub start_col: AnnotationColumn,
pub end_col: AnnotationColumn,
pub is_primary: bool,
pub label: Option<String>,
pub overlaps_exactly: bool,
@ -36,7 +62,12 @@ impl MultilineAnnotation {
pub fn as_start(&self) -> Annotation {
Annotation {
start_col: self.start_col,
end_col: self.start_col + 1,
end_col: AnnotationColumn {
// these might not correspond to the same place anymore,
// but that's okay for our purposes
display: self.start_col.display + 1,
file: self.start_col.file + 1,
},
is_primary: self.is_primary,
label: None,
annotation_type: AnnotationType::MultilineStart(self.depth),
@ -45,7 +76,12 @@ impl MultilineAnnotation {
pub fn as_end(&self) -> Annotation {
Annotation {
start_col: self.end_col.saturating_sub(1),
start_col: AnnotationColumn {
// these might not correspond to the same place anymore,
// but that's okay for our purposes
display: self.end_col.display.saturating_sub(1),
file: self.end_col.file.saturating_sub(1),
},
end_col: self.end_col,
is_primary: self.is_primary,
label: self.label.clone(),
@ -55,8 +91,8 @@ impl MultilineAnnotation {
pub fn as_line(&self) -> Annotation {
Annotation {
start_col: 0,
end_col: 0,
start_col: Default::default(),
end_col: Default::default(),
is_primary: self.is_primary,
label: None,
annotation_type: AnnotationType::MultilineLine(self.depth),
@ -92,14 +128,14 @@ pub enum AnnotationType {
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Annotation {
/// Start column, 0-based indexing -- counting *characters*, not
/// utf-8 bytes. Note that it is important that this field goes
/// Start column.
/// Note that it is important that this field goes
/// first, so that when we sort, we sort orderings by start
/// column.
pub start_col: usize,
pub start_col: AnnotationColumn,
/// End column within the line (exclusive)
pub end_col: usize,
pub end_col: AnnotationColumn,
/// Is this annotation derived from primary span
pub is_primary: bool,
@ -118,12 +154,13 @@ impl Annotation {
matches!(self.annotation_type, AnnotationType::MultilineLine(_))
}
/// Length of this annotation as displayed in the stderr output
pub fn len(&self) -> usize {
// Account for usize underflows
if self.end_col > self.start_col {
self.end_col - self.start_col
if self.end_col.display > self.start_col.display {
self.end_col.display - self.start_col.display
} else {
self.start_col - self.end_col
self.start_col.display - self.end_col.display
}
}

View File

@ -245,6 +245,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
}
fn suggest_missing_writer(
&self,
rcvr_ty: Ty<'tcx>,
args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
let mut err =
struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str);
err.span_note(
args.0.span,
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
);
if let ExprKind::Lit(_) = args.0.kind {
err.span_help(
args.0.span.shrink_to_lo(),
"a writer is needed before this format string",
);
};
err
}
pub fn report_no_match_method_error(
&self,
mut span: Span,
@ -323,16 +345,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
let mut err = struct_span_err!(
tcx.sess,
span,
E0599,
"no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
rcvr_ty.prefix_string(self.tcx),
ty_str_reported,
);
let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.map_or(false, |def_id| {
tcx.is_diagnostic_item(sym::write_macro, def_id)
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
}) && item_name.name == Symbol::intern("write_fmt");
let mut err = if is_write
&& let Some(args) = args
{
self.suggest_missing_writer(rcvr_ty, args)
} else {
struct_span_err!(
tcx.sess,
span,
E0599,
"no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
rcvr_ty.prefix_string(self.tcx),
ty_str_reported,
)
};
if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
}

View File

@ -1,6 +1,6 @@
use crate::mir::Mutability;
use crate::ty::subst::GenericArgKind;
use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitableExt};
use rustc_hir::def_id::DefId;
use std::fmt::Debug;
use std::hash::Hash;
@ -188,22 +188,24 @@ pub struct DeepRejectCtxt {
}
impl DeepRejectCtxt {
pub fn generic_args_may_unify<'tcx>(
pub fn substs_refs_may_unify<'tcx>(
self,
obligation_arg: ty::GenericArg<'tcx>,
impl_arg: ty::GenericArg<'tcx>,
obligation_substs: SubstsRef<'tcx>,
impl_substs: SubstsRef<'tcx>,
) -> bool {
match (obligation_arg.unpack(), impl_arg.unpack()) {
// We don't fast reject based on regions for now.
(GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true,
(GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => {
self.types_may_unify(obl, imp)
iter::zip(obligation_substs, impl_substs).all(|(obl, imp)| {
match (obl.unpack(), imp.unpack()) {
// We don't fast reject based on regions for now.
(GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true,
(GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => {
self.types_may_unify(obl, imp)
}
(GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => {
self.consts_may_unify(obl, imp)
}
_ => bug!("kind mismatch: {obl} {imp}"),
}
(GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => {
self.consts_may_unify(obl, imp)
}
_ => bug!("kind mismatch: {obligation_arg} {impl_arg}"),
}
})
}
pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool {
@ -258,9 +260,7 @@ impl DeepRejectCtxt {
},
ty::Adt(obl_def, obl_substs) => match k {
&ty::Adt(impl_def, impl_substs) => {
obl_def == impl_def
&& iter::zip(obl_substs, impl_substs)
.all(|(obl, imp)| self.generic_args_may_unify(obl, imp))
obl_def == impl_def && self.substs_refs_may_unify(obl_substs, impl_substs)
}
_ => false,
},

View File

@ -17,7 +17,6 @@ use rustc_middle::ty::ProjectionPredicate;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
use rustc_span::{sym, DUMMY_SP};
use std::iter;
impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
@ -144,9 +143,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
{
if !drcx.substs_refs_may_unify(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs) {
return Err(NoSolution);
}

View File

@ -47,6 +47,22 @@ impl<'tcx> SearchGraph<'tcx> {
self.mode
}
/// We do not use the global cache during coherence.
///
/// The trait solver behavior is different for coherence
/// so we would have to add the solver mode to the cache key.
/// This is probably not worth it as trait solving during
/// coherence tends to already be incredibly fast.
///
/// We could add another global cache for coherence instead,
/// but that's effort so let's only do it if necessary.
pub(super) fn should_use_global_cache(&self) -> bool {
match self.mode {
SolverMode::Normal => true,
SolverMode::Coherence => false,
}
}
pub(super) fn is_empty(&self) -> bool {
self.stack.is_empty() && self.provisional_cache.is_empty()
}
@ -191,8 +207,10 @@ impl<'tcx> SearchGraph<'tcx> {
canonical_goal: CanonicalGoal<'tcx>,
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) {
return result;
if self.should_use_global_cache() {
if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) {
return result;
}
}
match self.try_push_stack(tcx, canonical_goal) {
@ -252,9 +270,8 @@ impl<'tcx> SearchGraph<'tcx> {
// dependencies, our non-root goal may no longer appear as child of the root goal.
//
// See https://github.com/rust-lang/rust/pull/108071 for some additional context.
let should_cache_globally = matches!(self.solver_mode(), SolverMode::Normal)
&& (!self.overflow_data.did_overflow() || self.stack.is_empty());
if should_cache_globally {
let can_cache = !self.overflow_data.did_overflow() || self.stack.is_empty();
if self.should_use_global_cache() && can_cache {
tcx.new_solver_evaluation_cache.insert(
current_goal.goal,
dep_node,

View File

@ -1,7 +1,5 @@
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
use std::iter;
use super::{assembly, EvalCtxt, SolverMode};
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
@ -41,9 +39,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
{
if !drcx.substs_refs_may_unify(
goal.predicate.trait_ref.substs,
impl_trait_ref.skip_binder().substs,
) {
return Err(NoSolution);
}

View File

@ -79,8 +79,9 @@ pub fn overlapping_impls(
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
let may_overlap = match (impl1_ref, impl2_ref) {
(Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
.all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
(Some(a), Some(b)) => {
drcx.substs_refs_may_unify(a.skip_binder().substs, b.skip_binder().substs)
}
(None, None) => {
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();

View File

@ -11,7 +11,7 @@ use hir::LangItem;
use rustc_hir as hir;
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
use rustc_middle::ty::fast_reject::TreatProjections;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use crate::traits;
@ -344,6 +344,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
let obligation_substs = obligation.predicate.skip_binder().trait_ref.substs;
self.tcx().for_each_relevant_impl(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),
@ -352,7 +354,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// consider a "quick reject". This avoids creating more types
// and so forth that we need to.
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) {
return;
}
if self.reject_fn_ptr_impls(

View File

@ -45,7 +45,6 @@ use rustc_infer::traits::TraitEngineExt;
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::SubstsRef;
@ -2533,19 +2532,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
Ok(Normalized { value: impl_substs, obligations: nested_obligations })
}
fn fast_reject_trait_refs(
&mut self,
obligation: &TraitObligation<'tcx>,
impl_trait_ref: &ty::TraitRef<'tcx>,
) -> bool {
// We can avoid creating type variables and doing the full
// substitution if we find that any of the input types, when
// simplified, do not match.
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs)
.any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp))
}
/// Normalize `where_clause_trait_ref` and try to match it against
/// `obligation`. If successful, return any predicates that
/// result from the normalization.

View File

@ -0,0 +1,8 @@
include ../../run-make-fulldeps/tools.mk
# only-linux
# Test compiler behavior in case: `jobserver-auth` points to correct pipe which is not jobserver.
all:
bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3</dev/null' 2>&1 | diff jobserver.stderr -

View File

@ -0,0 +1,4 @@
error: failed to acquire jobserver token: early EOF on jobserver pipe
error: aborting due to previous error

View File

@ -1,5 +1,5 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/dont-project-to-specializable-projection.rs:4:12
--> $DIR/dont-project-to-specializable-projection.rs:6:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)]
= note: `#[warn(incomplete_features)]` on by default
error: async associated function in trait cannot be specialized
--> $DIR/dont-project-to-specializable-projection.rs:14:5
--> $DIR/dont-project-to-specializable-projection.rs:16:5
|
LL | default async fn foo(_: T) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,34 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/dont-project-to-specializable-projection.rs:6: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[E0053]: method `foo` has an incompatible type for trait
--> $DIR/dont-project-to-specializable-projection.rs:16:35
|
LL | default async fn foo(_: T) -> &'static str {
| ^^^^^^^^^^^^ expected associated type, found future
|
note: type in trait
--> $DIR/dont-project-to-specializable-projection.rs:12:27
|
LL | async fn foo(_: T) -> &'static str;
| ^^^^^^^^^^^^
= note: expected signature `fn(_) -> impl Future<Output = &'static str>`
found signature `fn(_) -> impl Future<Output = &'static str>`
error: async associated function in trait cannot be specialized
--> $DIR/dont-project-to-specializable-projection.rs:16:5
|
LL | default async fn foo(_: T) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: specialization behaves in inconsistent and surprising ways with `#![feature(async_fn_in_trait)]`, and for now is disallowed
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0053`.

View File

@ -1,5 +1,7 @@
// edition: 2021
// known-bug: #108309
// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
// revisions: current next
#![feature(async_fn_in_trait)]
#![feature(min_specialization)]

View File

@ -0,0 +1,6 @@
// ignore-tidy-tab
pub struct S;
impl S {
fn method(&self) {}
}

View File

@ -0,0 +1,12 @@
// Test for #109537: ensure that column numbers are correctly generated when using hard tabs.
// aux-build:tab_column_numbers.rs
// ignore-tidy-tab
extern crate tab_column_numbers;
fn main() {
let s = tab_column_numbers::S;
s.method();
//~^ ERROR method `method` is private
}

View File

@ -0,0 +1,14 @@
error[E0624]: method `method` is private
--> $DIR/tab-column-numbers.rs:10:4
|
LL | s.method();
| ^^^^^^ private method
|
::: $DIR/auxiliary/tab_column_numbers.rs:5:3
|
LL | fn method(&self) {}
| ---------------- private method defined here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0624`.

View File

@ -0,0 +1,17 @@
// Check error for missing writer in writeln! and write! macro
fn main() {
let x = 1;
let y = 2;
write!("{}_{}", x, y);
//~^ ERROR format argument must be a string literal
//~| HELP you might be missing a string literal to format with
//~| ERROR cannot write into `&'static str`
//~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
//~| HELP a writer is needed before this format string
writeln!("{}_{}", x, y);
//~^ ERROR format argument must be a string literal
//~| HELP you might be missing a string literal to format with
//~| ERROR cannot write into `&'static str`
//~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
//~| HELP a writer is needed before this format string
}

View File

@ -0,0 +1,59 @@
error: format argument must be a string literal
--> $DIR/missing-writer.rs:5:21
|
LL | write!("{}_{}", x, y);
| ^
|
help: you might be missing a string literal to format with
|
LL | write!("{}_{}", "{} {}", x, y);
| ++++++++
error: format argument must be a string literal
--> $DIR/missing-writer.rs:11:23
|
LL | writeln!("{}_{}", x, y);
| ^
|
help: you might be missing a string literal to format with
|
LL | writeln!("{}_{}", "{} {}", x, y);
| ++++++++
error[E0599]: cannot write into `&'static str`
--> $DIR/missing-writer.rs:5:12
|
LL | write!("{}_{}", x, y);
| -------^^^^^^^------- method not found in `&str`
|
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
--> $DIR/missing-writer.rs:5:12
|
LL | write!("{}_{}", x, y);
| ^^^^^^^
help: a writer is needed before this format string
--> $DIR/missing-writer.rs:5:12
|
LL | write!("{}_{}", x, y);
| ^
error[E0599]: cannot write into `&'static str`
--> $DIR/missing-writer.rs:11:14
|
LL | writeln!("{}_{}", x, y);
| ---------^^^^^^^------- method not found in `&str`
|
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
--> $DIR/missing-writer.rs:11:14
|
LL | writeln!("{}_{}", x, y);
| ^^^^^^^
help: a writer is needed before this format string
--> $DIR/missing-writer.rs:11:14
|
LL | writeln!("{}_{}", x, y);
| ^
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0599`.

View File

@ -21,18 +21,22 @@ note: required by a bound in `BufWriter`
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied
--> $DIR/mut-borrow-needed-by-trait.rs:21:5
--> $DIR/mut-borrow-needed-by-trait.rs:21:14
|
LL | writeln!(fp, "hello world").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
| ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
|
= note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
|
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
--> $DIR/mut-borrow-needed-by-trait.rs:21:14
|
LL | writeln!(fp, "hello world").unwrap();
| ^^
= note: the following trait bounds were not satisfied:
`&dyn std::io::Write: std::io::Write`
which is required by `BufWriter<&dyn std::io::Write>: std::io::Write`
= note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors