Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
- index f71cce8273..2995b25308 100644
- --- a/src/librustc/infer/error_reporting/mod.rs
- +++ b/src/librustc/infer/error_reporting/mod.rs
- @@ -511,6 +511,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
- }
- }
- },
- + ObligationCauseCode::IfExpression { then, outer, semicolon } => {
- + err.span_label(then, "expected because of this");
- + outer.map(|sp| err.span_label(sp, "if and else have incompatible types"));
- + if let Some(sp) = semicolon {
- + err.span_suggestion_short_with_applicability(
- + sp,
- + "consider removing this semicolon",
- + String::new(),
- + Applicability::MachineApplicable,
- + );
- + }
- + }
- _ => (),
- }
- }
- @@ -1460,7 +1472,7 @@ impl<'tcx> ObligationCause<'tcx> {
- }
- _ => "match arms have incompatible types",
- }),
- - IfExpression => Error0308("if and else have incompatible types"),
- + IfExpression { .. } => Error0308("if and else have incompatible types"),
- IfExpressionWithNoElse => Error0317("if may be missing an else clause"),
- MainFunctionType => Error0580("main function has wrong type"),
- StartFunctionType => Error0308("start function has wrong type"),
- @@ -1488,7 +1500,7 @@ impl<'tcx> ObligationCause<'tcx> {
- hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",
- _ => "match arms have compatible types",
- },
- - IfExpression => "if and else have compatible types",
- + IfExpression { .. } => "if and else have compatible types",
- IfExpressionWithNoElse => "if missing an else returns ()",
- MainFunctionType => "`main` function has the correct type",
- StartFunctionType => "`start` function has the correct type",
- diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
- index a373faab3a..4c14c19688 100644
- --- a/src/librustc/lint/mod.rs
- +++ b/src/librustc/lint/mod.rs
- @@ -453,7 +453,7 @@ impl Level {
- }
- /// How a lint level was set.
- -#[derive(Clone, Copy, PartialEq, Eq)]
- +#[derive(Clone, Copy, PartialEq, Eq, Debug)]
- pub enum LintSource {
- /// Lint is at the default level as declared
- /// in rustc or a plugin.
- @@ -523,6 +523,8 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
- msg: &str)
- -> DiagnosticBuilder<'a>
- {
- + debug!("struct_lint_level lint: {:?} level: {:?} src: {:?} span: {:?} msg: {:?}",
- + lint, level, src, span, msg);
- let mut err = match (level, span) {
- (Level::Allow, _) => return sess.diagnostic().struct_dummy(),
- (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
- @@ -533,6 +535,8 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
- (Level::Forbid, None) => sess.struct_err(msg),
- };
- + debug!("struct_lint_level err: {:?}", err);
- +
- let name = lint.name_lower();
- match src {
- LintSource::Default => {
- @@ -606,22 +610,140 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
- err.note(&citation);
- }
- + debug!("struct_lint_level prior to primary_spans check, err: {:?}", err);
- +
- + #[derive(Copy, Clone, Debug)]
- + /// This is a simple hierarchy for tracking whether the set of
- + /// primary spans should be considered to have been affected by a
- + /// macro defined by an external crate.
- + ///
- + /// The hierarchy looks like this:
- + ///
- + /// ```
- + /// HasSomeCurrentExtern
- + /// |
- + /// HasSomeHistoricalExtern
- + /// |
- + /// NoExterns
- + /// ```
- + ///
- + /// Combining two primary spans will choose whichever one is
- + /// higher in the hierarchy structure.
- + ///
- + /// The spans we associate with a given lint can change over time,
- + /// and those spans can affect whether a lint is actually
- + /// signalled. This state is used as part of ensuring that we
- + /// don't inject hard-errors into stable code that is denying (or
- + /// forbidding) a given lint, by tracking old spans that had been
- + /// used in previous versions of `rustc` and then making sure that
- + /// if an old span would cause a lint to be suppressed, then we
- + /// will not allow a previously-suppressed lint to suddenly become
- + /// a hard error.
- + enum ExternState {
- + /// At least one primary span associated with the error
- + /// originated from a macro defined by an external crate.
- + HasSomeCurrentExtern,
- +
- + /// None of the primary spans currently associated with error
- + /// originated with a macro from an external crate, *but* in
- + /// an earlier version of the compiler, there was some primary
- + /// span associated with the error that did originate from a
- + /// macro defined by an external crate.
- + HasSomeHistoricalExtern,
- +
- + /// None of the primary spans (neither currently nor in the
- + /// recorded history of the error's construction) originated
- + /// from a macro defined by an external crate.
- + NoExterns,
- + }
- +
- + impl ExternState {
- + /// Returns the higher point in the `ExternState` hierarchy.
- + fn combine(&self, other: ExternState) -> ExternState {
- + match (*self, other) {
- + (ExternState::HasSomeCurrentExtern, _) |
- + (_, ExternState::HasSomeCurrentExtern) => ExternState::HasSomeCurrentExtern,
- + (ExternState::HasSomeHistoricalExtern, _) |
- + (_, ExternState::HasSomeHistoricalExtern) => ExternState::HasSomeHistoricalExtern,
- + (ExternState::NoExterns, ExternState::NoExterns) => ExternState::NoExterns,
- + }
- + }
- +
- + /// Indicates whether the primary spans indicate that we
- + /// should not emit suggstions for use by `rustfix`.
- + fn disallow_suggestions(&self) -> bool {
- + match *self {
- + ExternState::HasSomeCurrentExtern => true,
- + ExternState::HasSomeHistoricalExtern => false,
- + ExternState::NoExterns => false,
- + }
- + }
- + }
- +
- // If this code originates in a foreign macro, aka something that this crate
- // did not itself author, then it's likely that there's nothing this crate
- // can do about it. We probably want to skip the lint entirely.
- - if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
- + let old_control = err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s));
- + let extern_state = err.span.primary_spans_with_migrations()
- + .enumerate()
- + .inspect(|(i, s)| {
- + debug!("struct_lint_level primary_span[{}]: {:?}, in_external_macro: {:?}",
- + i, s, (in_external_macro(sess, s.new),
- + s.old.map(|s|in_external_macro(sess, s))));
- + })
- + .fold(ExternState::NoExterns,
- + |ext_state, (_, migrate_span)| {
- + let new_state = if in_external_macro(sess, migrate_span.new) {
- + ExternState::HasSomeCurrentExtern
- + } else if migrate_span.old.map_or(false, |s| in_external_macro(sess, s)) {
- + ExternState::HasSomeHistoricalExtern
- + } else {
- + ExternState::NoExterns
- + };
- +
- + ext_state.combine(new_state)
- + });
- +
- + debug!("struct_lint_level old_control: {:?} extern_state: {:?} err: {:?}",
- + old_control, extern_state, err);
- +
- + if extern_state.disallow_suggestions() {
- // Any suggestions made here are likely to be incorrect, so anything we
- // emit shouldn't be automatically fixed by rustfix.
- err.allow_suggestions(false);
- + }
- +
- + // If this is a future incompatible lint it'll become a hard error, so
- + // we have to emit *something*. Also allow lints to whitelist themselves
- + // on a case-by-case basis for emission in a foreign macro.
- + if future_incompatible.is_none() && !lint.report_in_external_macro {
- + match extern_state {
- + ExternState::NoExterns => { }
- - // If this is a future incompatible lint it'll become a hard error, so
- - // we have to emit *something*. Also allow lints to whitelist themselves
- - // on a case-by-case basis for emission in a foreign macro.
- - if future_incompatible.is_none() && !lint.report_in_external_macro {
- - err.cancel()
- + ExternState::HasSomeCurrentExtern => {
- + err.cancel()
- + }
- +
- + ExternState::HasSomeHistoricalExtern => {
- + if err.is_error() {
- + err.level = errors::Level::Warning;
- + err.warn(
- + "this lint has been downgraded to a warning for backwards \
- + compatibility with previous releases",
- + );
- + }
- + // note that we deliberately do not cancel these;
- + // there is no *current* primary span from an external
- + // crate, and thus it is best for the overall
- + // user-experience that we issue some form of
- + // diagnostic, as long as it does not lead to a
- + // hard-error.
- + }
- }
- }
- + debug!("struct_lint_level finis err: {:?}", err);
- +
- return err
- }
- diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
- index 7d9e80fd60..367a7eacdf 100644
- --- a/src/librustc/traits/error_reporting.rs
- +++ b/src/librustc/traits/error_reporting.rs
- @@ -1445,7 +1445,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
- ObligationCauseCode::ExprAssignable |
- ObligationCauseCode::MatchExpressionArm { .. } |
- ObligationCauseCode::MatchExpressionArmPattern { .. } |
- - ObligationCauseCode::IfExpression |
- + ObligationCauseCode::IfExpression { .. } |
- ObligationCauseCode::IfExpressionWithNoElse |
- ObligationCauseCode::MainFunctionType |
- ObligationCauseCode::StartFunctionType |
- diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
- index 14c25b77a1..68383bef37 100644
- --- a/src/librustc/traits/mod.rs
- +++ b/src/librustc/traits/mod.rs
- @@ -229,7 +229,11 @@ pub enum ObligationCauseCode<'tcx> {
- MatchExpressionArmPattern { span: Span, ty: Ty<'tcx> },
- /// Computing common supertype in an if expression
- - IfExpression,
- + IfExpression {
- + then: Span,
- + outer: Option<Span>,
- + semicolon: Option<Span>,
- + },
- /// Computing common supertype of an if expression with no else counter-part
- IfExpressionWithNoElse,
- diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
- index 277e2ed0e8..2f5df02221 100644
- --- a/src/librustc/traits/structural_impls.rs
- +++ b/src/librustc/traits/structural_impls.rs
- @@ -520,7 +520,11 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
- super::MatchExpressionArmPattern { span, ty } => {
- tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty })
- }
- - super::IfExpression => Some(super::IfExpression),
- + super::IfExpression { then, outer, semicolon } => Some(super::IfExpression {
- + then,
- + outer,
- + semicolon,
- + }),
- super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
- super::MainFunctionType => Some(super::MainFunctionType),
- super::StartFunctionType => Some(super::StartFunctionType),
- diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs
- index 2694a04b94..922c760485 100644
- --- a/src/librustc_lint/nonstandard_style.rs
- +++ b/src/librustc_lint/nonstandard_style.rs
- @@ -211,8 +211,12 @@ impl NonSnakeCase {
- } else {
- format!("{} `{}` should have a snake case name", sort, name)
- };
- + // let _migrate_span = MigrateSpan { new: ident.span, old: old_span };
- +
- match span {
- - Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
- + Some(span) => {
- + cx.struct_span_lint(NON_SNAKE_CASE, span, &msg).emit();
- + }
- None => cx.lint(NON_SNAKE_CASE, &msg),
- }
- }
- diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
- index dbbb7f42fe..1b07385d4d 100644
- --- a/src/librustc_typeck/check/mod.rs
- +++ b/src/librustc_typeck/check/mod.rs
- @@ -3366,13 +3366,103 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- let coerce_to_ty = expected.coercion_target_type(self, sp);
- let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty);
- - let if_cause = self.cause(sp, ObligationCauseCode::IfExpression);
- - coerce.coerce(self, &if_cause, then_expr, then_ty);
- + coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
- if let Some(else_expr) = opt_else_expr {
- let else_ty = self.check_expr_with_expectation(else_expr, expected);
- let else_diverges = self.diverges.get();
- + let mut outer_sp = if self.tcx.sess.source_map().is_multiline(sp) {
- + // The `if`/`else` isn't in one line in the output, include some context to make it
- + // clear it is an if/else expression:
- + // ```
- + // LL | let x = if true {
- + // | _____________-
- + // LL || 10i32
- + // || ----- expected because of this
- + // LL || } else {
- + // LL || 10u32
- + // || ^^^^^ expected i32, found u32
- + // LL || };
- + // ||_____- if and else have incompatible types
- + // ```
- + Some(sp)
- + } else {
- + // The entire expression is in one line, only point at the arms
- + // ```
- + // LL | let x = if true { 10i32 } else { 10u32 };
- + // | ----- ^^^^^ expected i32, found u32
- + // | |
- + // | expected because of this
- + // ```
- + None
- + };
- + let mut remove_semicolon = None;
- + let error_sp = if let ExprKind::Block(block, _) = &else_expr.node {
- + if let Some(expr) = &block.expr {
- + expr.span
- + } else if let Some(stmt) = block.stmts.last() {
- + // possibly incorrect trailing `;` in the else arm
- + remove_semicolon = self.could_remove_semicolon(block, then_ty);
- + stmt.span
- + } else { // empty block, point at its entirety
- + // Avoid overlapping spans that aren't as readable:
- + // ```
- + // 2 | let x = if true {
- + // | _____________-
- + // 3 | | 3
- + // | | - expected because of this
- + // 4 | | } else {
- + // | |____________^
- + // 5 | ||
- + // 6 | || };
- + // | || ^
- + // | ||_____|
- + // | |______if and else have incompatible types
- + // | expected integer, found ()
- + // ```
- + // by not pointing at the entire expression:
- + // ```
- + // 2 | let x = if true {
- + // | ------- if and else have incompatible types
- + // 3 | 3
- + // | - expected because of this
- + // 4 | } else {
- + // | ____________^
- + // 5 | |
- + // 6 | | };
- + // | |_____^ expected integer, found ()
- + // ```
- + if outer_sp.is_some() {
- + outer_sp = Some(self.tcx.sess.source_map().def_span(sp));
- + }
- + else_expr.span
- + }
- + } else { // shouldn't happen unless the parser has done something weird
- + else_expr.span
- + };
- + let then_sp = if let ExprKind::Block(block, _) = &then_expr.node {
- + if let Some(expr) = &block.expr {
- + expr.span
- + } else if let Some(stmt) = block.stmts.last() {
- + // possibly incorrect trailing `;` in the else arm
- + remove_semicolon = remove_semicolon.or(
- + self.could_remove_semicolon(block, else_ty));
- + stmt.span
- + } else { // empty block, point at its entirety
- + outer_sp = None; // same as in `error_sp`, cleanup output
- + then_expr.span
- + }
- + } else { // shouldn't happen unless the parser has done something weird
- + then_expr.span
- + };
- +
- + let if_cause = self.cause(error_sp, ObligationCauseCode::IfExpression {
- + then: then_sp,
- + outer: outer_sp,
- + semicolon: remove_semicolon,
- + });
- +
- coerce.coerce(self, &if_cause, else_expr, else_ty);
- // We won't diverge unless both branches do (or the condition does).
- @@ -5144,7 +5234,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- }
- }
- -
- /// A common error is to add an extra semicolon:
- ///
- /// ```
- @@ -5156,31 +5245,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- /// This routine checks if the final statement in a block is an
- /// expression with an explicit semicolon whose type is compatible
- /// with `expected_ty`. If so, it suggests removing the semicolon.
- - fn consider_hint_about_removing_semicolon(&self,
- - blk: &'gcx hir::Block,
- - expected_ty: Ty<'tcx>,
- - err: &mut DiagnosticBuilder) {
- + fn consider_hint_about_removing_semicolon(
- + &self,
- + blk: &'gcx hir::Block,
- + expected_ty: Ty<'tcx>,
- + err: &mut DiagnosticBuilder,
- + ) {
- + if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
- + err.span_suggestion_with_applicability(
- + span_semi,
- + "consider removing this semicolon",
- + String::new(),
- + Applicability::MachineApplicable,
- + );
- + }
- + }
- +
- + fn could_remove_semicolon(
- + &self,
- + blk: &'gcx hir::Block,
- + expected_ty: Ty<'tcx>,
- + ) -> Option<Span> {
- // Be helpful when the user wrote `{... expr;}` and
- // taking the `;` off is enough to fix the error.
- let last_stmt = match blk.stmts.last() {
- Some(s) => s,
- - None => return,
- + None => return None,
- };
- let last_expr = match last_stmt.node {
- hir::StmtKind::Semi(ref e, _) => e,
- - _ => return,
- + _ => return None,
- };
- let last_expr_ty = self.node_ty(last_expr.hir_id);
- if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() {
- - return;
- + return None;
- }
- let original_span = original_sp(last_stmt.span, blk.span);
- - let span_semi = original_span.with_lo(original_span.hi() - BytePos(1));
- - err.span_suggestion_with_applicability(
- - span_semi,
- - "consider removing this semicolon",
- - String::new(),
- - Applicability::MachineApplicable);
- + Some(original_span.with_lo(original_span.hi() - BytePos(1)))
- }
- // Instantiates the given path, which must refer to an item with the given
- diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
- index 6a41a93f0b..23593f6bac 100644
- --- a/src/libsyntax_pos/lib.rs
- +++ b/src/libsyntax_pos/lib.rs
- @@ -264,6 +264,7 @@ impl Ord for Span {
- pub struct MultiSpan {
- primary_spans: Vec<Span>,
- span_labels: Vec<(Span, String)>,
- + old_spans: Vec<Span>,
- }
- impl Span {
- @@ -636,21 +637,32 @@ impl MultiSpan {
- pub fn new() -> MultiSpan {
- MultiSpan {
- primary_spans: vec![],
- - span_labels: vec![]
- + span_labels: vec![],
- + old_spans: vec![],
- }
- }
- pub fn from_span(primary_span: Span) -> MultiSpan {
- MultiSpan {
- primary_spans: vec![primary_span],
- - span_labels: vec![]
- + span_labels: vec![],
- + old_spans: vec![],
- + }
- + }
- +
- + pub fn from_span_migrating(primary_span: Span, old_span: Span) -> MultiSpan {
- + MultiSpan {
- + primary_spans: vec![primary_span],
- + span_labels: vec![],
- + old_spans: vec![old_span],
- }
- }
- pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
- MultiSpan {
- primary_spans: vec,
- - span_labels: vec![]
- + span_labels: vec![],
- + old_spans: vec![],
- }
- }
- @@ -668,6 +680,19 @@ impl MultiSpan {
- &self.primary_spans
- }
- + /// Returns all primary spans; also includes, when present, any
- + /// span that the compiler had previously used in the place of
- + /// that primary span.
- + pub fn primary_spans_with_migrations(&self) -> impl Iterator<Item=MigrateSpan> {
- + let mut vec = Vec::new();
- + let mut old_spans = self.old_spans.iter().fuse();
- + for &new in &self.primary_spans {
- + let old = old_spans.next().map(|&s|s);
- + vec.push(MigrateSpan { new, old })
- + }
- + vec.into_iter()
- + }
- +
- /// Returns `true` if this contains only a dummy primary span with any hygienic context.
- pub fn is_dummy(&self) -> bool {
- let mut is_dummy = true;
- @@ -740,6 +765,22 @@ impl From<Vec<Span>> for MultiSpan {
- }
- }
- +// To be fully general, I suppose `old` might need to be a vector
- +// instead of a single span (i.e. when we've revised the span of a
- +// given lint twice across two stable versions of the compiler). But
- +// lets put off that work until we actually find a need for it.
- +#[derive(Debug)]
- +pub struct MigrateSpan { pub new: Span, pub old: Option<Span> }
- +
- +impl From<MigrateSpan> for MultiSpan {
- + fn from(MigrateSpan { new, old }: MigrateSpan) -> MultiSpan {
- + match old {
- + Some(old) => MultiSpan::from_span_migrating(new, old),
- + None => MultiSpan::from_span(new),
- + }
- + }
- +}
- +
- pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
- /// Identifies an offset of a multi-byte character in a `SourceFile`.
- diff --git a/src/test/ui/if-else-type-mismatch.rs b/src/test/ui/if-else-type-mismatch.rs
- new file mode 100644
- index 0000000000..583c3d0b76
- --- /dev/null
- +++ b/src/test/ui/if-else-type-mismatch.rs
- @@ -0,0 +1,46 @@
- +fn main() {
- + let _ = if true {
- + 1i32
- + } else {
- + 2u32
- + };
- + //~^^ ERROR if and else have incompatible types
- + let _ = if true { 42i32 } else { 42u32 };
- + //~^ ERROR if and else have incompatible types
- + let _ = if true {
- + 3u32;
- + } else {
- + 4u32
- + };
- + //~^^ ERROR if and else have incompatible types
- + let _ = if true {
- + 5u32
- + } else {
- + 6u32;
- + };
- + //~^^ ERROR if and else have incompatible types
- + let _ = if true {
- + 7i32;
- + } else {
- + 8u32
- + };
- + //~^^ ERROR if and else have incompatible types
- + let _ = if true {
- + 9i32
- + } else {
- + 10u32;
- + };
- + //~^^ ERROR if and else have incompatible types
- + let _ = if true {
- +
- + } else {
- + 11u32
- + };
- + //~^^ ERROR if and else have incompatible types
- + let _ = if true {
- + 12i32
- + } else {
- +
- + };
- + //~^^^ ERROR if and else have incompatible types
- +}
- diff --git a/src/test/ui/if-else-type-mismatch.stderr b/src/test/ui/if-else-type-mismatch.stderr
- new file mode 100644
- index 0000000000..b418c96118
- --- /dev/null
- +++ b/src/test/ui/if-else-type-mismatch.stderr
- @@ -0,0 +1,130 @@
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:5:9
- + |
- +LL | let _ = if true {
- + | _____________-
- +LL | | 1i32
- + | | ---- expected because of this
- +LL | | } else {
- +LL | | 2u32
- + | | ^^^^ expected i32, found u32
- +LL | | };
- + | |_____- if and else have incompatible types
- + |
- + = note: expected type `i32`
- + found type `u32`
- +
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:8:38
- + |
- +LL | let _ = if true { 42i32 } else { 42u32 };
- + | ----- ^^^^^ expected i32, found u32
- + | |
- + | expected because of this
- + |
- + = note: expected type `i32`
- + found type `u32`
- +
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:13:9
- + |
- +LL | let _ = if true {
- + | _____________-
- +LL | | 3u32;
- + | | -----
- + | | | |
- + | | | help: consider removing this semicolon
- + | | expected because of this
- +LL | | } else {
- +LL | | 4u32
- + | | ^^^^ expected (), found u32
- +LL | | };
- + | |_____- if and else have incompatible types
- + |
- + = note: expected type `()`
- + found type `u32`
- +
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:19:9
- + |
- +LL | let _ = if true {
- + | _____________-
- +LL | | 5u32
- + | | ---- expected because of this
- +LL | | } else {
- +LL | | 6u32;
- + | | ^^^^-
- + | | | |
- + | | | help: consider removing this semicolon
- + | | expected u32, found ()
- +LL | | };
- + | |_____- if and else have incompatible types
- + |
- + = note: expected type `u32`
- + found type `()`
- +
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:25:9
- + |
- +LL | let _ = if true {
- + | _____________-
- +LL | | 7i32;
- + | | ----- expected because of this
- +LL | | } else {
- +LL | | 8u32
- + | | ^^^^ expected (), found u32
- +LL | | };
- + | |_____- if and else have incompatible types
- + |
- + = note: expected type `()`
- + found type `u32`
- +
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:31:9
- + |
- +LL | let _ = if true {
- + | _____________-
- +LL | | 9i32
- + | | ---- expected because of this
- +LL | | } else {
- +LL | | 10u32;
- + | | ^^^^^^ expected i32, found ()
- +LL | | };
- + | |_____- if and else have incompatible types
- + |
- + = note: expected type `i32`
- + found type `()`
- +
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:37:9
- + |
- +LL | let _ = if true {
- + | _____________________-
- +LL | |
- +LL | | } else {
- + | |_____- expected because of this
- +LL | 11u32
- + | ^^^^^ expected (), found u32
- + |
- + = note: expected type `()`
- + found type `u32`
- +
- +error[E0308]: if and else have incompatible types
- + --> $DIR/if-else-type-mismatch.rs:42:12
- + |
- +LL | let _ = if true {
- + | ------- if and else have incompatible types
- +LL | 12i32
- + | ----- expected because of this
- +LL | } else {
- + | ____________^
- +LL | |
- +LL | | };
- + | |_____^ expected i32, found ()
- + |
- + = note: expected type `i32`
- + found type `()`
- +
- +error: aborting due to 8 previous errors
- +
- +For more information about this error, try `rustc --explain E0308`.
- diff --git a/src/test/ui/if/if-branch-types.stderr b/src/test/ui/if/if-branch-types.stderr
- index 44e172da78..74b925f72f 100644
- --- a/src/test/ui/if/if-branch-types.stderr
- +++ b/src/test/ui/if/if-branch-types.stderr
- @@ -1,8 +1,10 @@
- error[E0308]: if and else have incompatible types
- - --> $DIR/if-branch-types.rs:2:13
- + --> $DIR/if-branch-types.rs:2:38
- |
- LL | let x = if true { 10i32 } else { 10u32 };
- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found u32
- + | ----- ^^^^^ expected i32, found u32
- + | |
- + | expected because of this
- |
- = note: expected type `i32`
- found type `u32`
- diff --git a/src/test/ui/lint/auxiliary/lints-in-foreign-macros-with-lint-attributes.rs b/src/test/ui/lint/auxiliary/lints-in-foreign-macros-with-lint-attributes.rs
- new file mode 100644
- index 0000000000..2f115e65f3
- --- /dev/null
- +++ b/src/test/ui/lint/auxiliary/lints-in-foreign-macros-with-lint-attributes.rs
- @@ -0,0 +1,74 @@
- +// This file declares a bunch of macros relevant to testing
- +// our precise behavior on cases explored as part of issue
- +// rust-lang/rust#58502
- +//
- +// In particular, this file is trying to explore how the
- +// lint-attributes (`#[allow(..)]`, `#[deny(..)]`, etc) attached to
- +// the context of a macro's definition-site interacts with similar
- +// lint-attributes attached to the context of a macro's use-site.
- +
- +#![crate_type="lib"]
- +
- +#[macro_export]
- +macro_rules! definition_context_silent_on_snakes {
- + ($name:ident) => {
- + pub fn $name() {}
- + };
- +}
- +
- +#[macro_export]
- +macro_rules! injecting_allow_nonsnakes {
- + ($name:ident) => {
- + #[allow(non_snake_case)]
- + pub fn $name() {}
- + };
- +}
- +
- +#[macro_export]
- +macro_rules! injecting_warn_nonsnakes {
- + ($name:ident) => {
- + #[warn(non_snake_case)]
- + pub fn $name() {}
- + };
- +}
- +
- +#[macro_export]
- +macro_rules! injecting_deny_nonsnakes {
- + ($name:ident) => {
- + #[deny(non_snake_case)]
- + pub fn $name() {}
- + };
- +}
- +
- +mod inner_allow {
- + #![allow(non_snake_case)]
- +
- + #[macro_export]
- + macro_rules! definition_context_allow_nonsnakes {
- + ($name:ident) => {
- + pub fn $name() {}
- + };
- + }
- +}
- +
- +mod inner_warn {
- + #![warn(non_snake_case)]
- +
- + #[macro_export]
- + macro_rules! definition_context_warn_nonsnakes {
- + ($name:ident) => {
- + pub fn $name() {}
- + };
- + }
- +}
- +
- +mod inner_deny {
- + #![warn(non_snake_case)]
- +
- + #[macro_export]
- + macro_rules! definition_context_deny_nonsnakes {
- + ($name:ident) => {
- + pub fn $name() {}
- + };
- + }
- +}
- diff --git a/src/test/ui/lint/issue-58502-lint-attrs-at-def-and-use-sites.rs b/src/test/ui/lint/issue-58502-lint-attrs-at-def-and-use-sites.rs
- new file mode 100644
- index 0000000000..a239dfc932
- --- /dev/null
- +++ b/src/test/ui/lint/issue-58502-lint-attrs-at-def-and-use-sites.rs
- @@ -0,0 +1,100 @@
- +// aux-build:lints-in-foreign-macros-with-lint-attributes.rs
- +
- +#[macro_use]
- +extern crate lints_in_foreign_macros_with_lint_attributes;
- +
- +definition_context_silent_on_snakes!(DefSilent_UseSilent);
- +//~^ WARN should have a snake case name
- +
- +injecting_allow_nonsnakes!(InjectsAllow_UseSilent); // OK
- +injecting_warn_nonsnakes!(InjectsWarn_UseSient);
- +//~^ WARN should have a snake case name
- +//~| NOTE lint level defined here
- +//~| NOTE originates in a macro outside of the current crate
- +injecting_deny_nonsnakes!(InjectsDeny_UseSient);
- +//~^ ERROR should have a snake case name
- +//~| NOTE lint level defined here
- +//~| NOTE originates in a macro outside of the current crate
- +
- +definition_context_allow_nonsnakes!(DefAllow_UseSilent);
- +//~^ WARN should have a snake case name
- +definition_context_warn_nonsnakes!(DefWarn_UseSilent);
- +//~^ WARN should have a snake case name
- +definition_context_deny_nonsnakes!(DefDeny_UseSilent);
- +//~^ WARN should have a snake case name
- +
- +mod use_allow {
- + #![allow(non_snake_case)]
- +
- + definition_context_silent_on_snakes!(DefSilent_UseAllow); // OK
- +
- + injecting_allow_nonsnakes!(InjectsAllow_UseAllow); // OK
- + injecting_warn_nonsnakes!(InjectsWarn_UseAllow);
- + //~^ WARN should have a snake case name
- + //~| NOTE lint level defined here
- + //~| NOTE originates in a macro outside of the current crate
- + injecting_deny_nonsnakes!(InjectsDeny_UseAllow);
- + //~^ ERROR should have a snake case name
- + //~| NOTE lint level defined here
- + //~| NOTE originates in a macro outside of the current crate
- +
- + definition_context_allow_nonsnakes!(DefAllow_UseAllow); // OK
- + definition_context_warn_nonsnakes!(DefWarn_UseAllow); // OK
- + definition_context_deny_nonsnakes!(DefDeny_UseAllow); // OK
- +}
- +
- +mod use_warn {
- + #![warn(non_snake_case)]
- + //~^ NOTE lint level defined here
- +
- + definition_context_silent_on_snakes!(DefSilent_UseWarn);
- + //~^ WARN should have a snake case name
- +
- + injecting_allow_nonsnakes!(InjectsAllow_UseWarn); // OK
- + injecting_warn_nonsnakes!(InjectsWarn_UseWarn);
- + //~^ WARN should have a snake case name
- + //~| NOTE lint level defined here
- + //~| NOTE originates in a macro outside of the current crate
- + injecting_deny_nonsnakes!(InjectsDeny_UseWarn);
- + //~^ ERROR should have a snake case name
- + //~| NOTE lint level defined here
- + //~| NOTE originates in a macro outside of the current crate
- +
- + definition_context_allow_nonsnakes!(DefAllow_UseWarn);
- + //~^ WARN should have a snake case name
- + definition_context_warn_nonsnakes!(DefWarn_UseWarn);
- + //~^ WARN should have a snake case name
- + definition_context_deny_nonsnakes!(DefDeny_UseWarn);
- + //~^ WARN should have a snake case name
- +}
- +
- +mod use_deny {
- + #![deny(non_snake_case)]
- + //~^ NOTE lint level defined here
- +
- + definition_context_silent_on_snakes!(DefSilent_UseDeny);
- + //~^ ERROR should have a snake case name
- +
- + injecting_allow_nonsnakes!(InjectsAllow_UseDeny); // OK
- + injecting_warn_nonsnakes!(InjectsWarn_UseDeny);
- + //~^ WARN should have a snake case name
- + //~| NOTE lint level defined here
- + //~| NOTE originates in a macro outside of the current crate
- + injecting_deny_nonsnakes!(InjectsDeny_UseDeny);
- + //~^ ERROR should have a snake case name
- + //~| NOTE lint level defined here
- + //~| NOTE originates in a macro outside of the current crate
- +
- + definition_context_allow_nonsnakes!(DefAllow_UseDeny);
- + //~^ ERROR should have a snake case name
- + definition_context_warn_nonsnakes!(DefWarn_UseDeny);
- + //~^ ERROR should have a snake case name
- + definition_context_deny_nonsnakes!(DefDeny_UseDeny);
- + //~^ ERROR should have a snake case name
- +}
- +
- +#[deny(non_snake_case)]
- +fn ForcedFailure() { }
- +
- +fn main() {
- +}
- diff --git a/src/test/ui/lint/issue-58502-lint-attrs-at-def-and-use-sites.stderr b/src/test/ui/lint/issue-58502-lint-attrs-at-def-and-use-sites.stderr
- new file mode 100644
- index 0000000000..161ce5e97f
- --- /dev/null
- +++ b/src/test/ui/lint/issue-58502-lint-attrs-at-def-and-use-sites.stderr
- @@ -0,0 +1,191 @@
- +warning: function `DefSilent_UseSilent` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:6:38
- + |
- +LL | definition_context_silent_on_snakes!(DefSilent_UseSilent);
- + | ^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_silent_use_silent`
- + |
- + = note: #[warn(non_snake_case)] on by default
- +
- +warning: function `InjectsWarn_UseSient` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:10:27
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseSient);
- + | ^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_warn_use_sient`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:10:1
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseSient);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +error: function `InjectsDeny_UseSient` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:14:27
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseSient);
- + | ^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_deny_use_sient`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:14:1
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseSient);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +warning: function `DefAllow_UseSilent` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:19:37
- + |
- +LL | definition_context_allow_nonsnakes!(DefAllow_UseSilent);
- + | ^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_allow_use_silent`
- +
- +warning: function `DefWarn_UseSilent` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:21:36
- + |
- +LL | definition_context_warn_nonsnakes!(DefWarn_UseSilent);
- + | ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_warn_use_silent`
- +
- +warning: function `DefDeny_UseSilent` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:23:36
- + |
- +LL | definition_context_deny_nonsnakes!(DefDeny_UseSilent);
- + | ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_deny_use_silent`
- +
- +warning: function `InjectsWarn_UseAllow` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:32:31
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseAllow);
- + | ^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_warn_use_allow`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:32:5
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseAllow);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +error: function `InjectsDeny_UseAllow` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:36:31
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseAllow);
- + | ^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_deny_use_allow`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:36:5
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseAllow);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +warning: function `DefSilent_UseWarn` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:50:42
- + |
- +LL | definition_context_silent_on_snakes!(DefSilent_UseWarn);
- + | ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_silent_use_warn`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:47:13
- + |
- +LL | #![warn(non_snake_case)]
- + | ^^^^^^^^^^^^^^
- +
- +warning: function `InjectsWarn_UseWarn` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:54:31
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseWarn);
- + | ^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_warn_use_warn`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:54:5
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseWarn);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +error: function `InjectsDeny_UseWarn` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:58:31
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseWarn);
- + | ^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_deny_use_warn`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:58:5
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseWarn);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +warning: function `DefAllow_UseWarn` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:63:41
- + |
- +LL | definition_context_allow_nonsnakes!(DefAllow_UseWarn);
- + | ^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_allow_use_warn`
- +
- +warning: function `DefWarn_UseWarn` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:65:40
- + |
- +LL | definition_context_warn_nonsnakes!(DefWarn_UseWarn);
- + | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_warn_use_warn`
- +
- +warning: function `DefDeny_UseWarn` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:67:40
- + |
- +LL | definition_context_deny_nonsnakes!(DefDeny_UseWarn);
- + | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_deny_use_warn`
- +
- +error: function `DefSilent_UseDeny` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:75:42
- + |
- +LL | definition_context_silent_on_snakes!(DefSilent_UseDeny);
- + | ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_silent_use_deny`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:72:13
- + |
- +LL | #![deny(non_snake_case)]
- + | ^^^^^^^^^^^^^^
- +
- +warning: function `InjectsWarn_UseDeny` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:79:31
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseDeny);
- + | ^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_warn_use_deny`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:79:5
- + |
- +LL | injecting_warn_nonsnakes!(InjectsWarn_UseDeny);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +error: function `InjectsDeny_UseDeny` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:83:31
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseDeny);
- + | ^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `injects_deny_use_deny`
- + |
- +note: lint level defined here
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:83:5
- + |
- +LL | injecting_deny_nonsnakes!(InjectsDeny_UseDeny);
- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
- +
- +error: function `DefAllow_UseDeny` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:88:41
- + |
- +LL | definition_context_allow_nonsnakes!(DefAllow_UseDeny);
- + | ^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_allow_use_deny`
- +
- +error: function `DefWarn_UseDeny` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:90:40
- + |
- +LL | definition_context_warn_nonsnakes!(DefWarn_UseDeny);
- + | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_warn_use_deny`
- +
- +error: function `DefDeny_UseDeny` should have a snake case name
- + --> $DIR/issue-58502-lint-attrs-at-def-and-use-sites.rs:92:40
- + |
- +LL | definition_context_deny_nonsnakes!(DefDeny_UseDeny);
- + | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `def_deny_use_deny`
- +
- +error: aborting due to 8 previous errors
- \ No newline at end of file
- diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.stderr
- index 40a3e7e964..60e70ddcd9 100644
- --- a/src/test/ui/regions/region-invariant-static-error-reporting.stderr
- +++ b/src/test/ui/regions/region-invariant-static-error-reporting.stderr
- @@ -1,13 +1,15 @@
- error[E0308]: if and else have incompatible types
- - --> $DIR/region-invariant-static-error-reporting.rs:14:15
- + --> $DIR/region-invariant-static-error-reporting.rs:17:9
- |
- LL | let bad = if x.is_some() {
- - | _______________^
- + | _______________-
- LL | | x.unwrap()
- + | | ---------- expected because of this
- LL | | } else {
- LL | | mk_static()
- + | | ^^^^^^^^^^^ lifetime mismatch
- LL | | };
- - | |_____^ lifetime mismatch
- + | |_____- if and else have incompatible types
- |
- = note: expected type `Invariant<'a>`
- found type `Invariant<'static>`
- diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr
- index 24d8db481b..87809d212d 100644
- --- a/src/test/ui/str/str-array-assignment.stderr
- +++ b/src/test/ui/str/str-array-assignment.stderr
- @@ -1,8 +1,10 @@
- error[E0308]: if and else have incompatible types
- - --> $DIR/str-array-assignment.rs:3:11
- + --> $DIR/str-array-assignment.rs:3:37
- |
- LL | let t = if true { s[..2] } else { s };
- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected str, found &str
- + | ------ ^ expected str, found &str
- + | |
- + | expected because of this
- |
- = note: expected type `str`
- found type `&str`
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement