Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e341923

Browse files
committed
Allow coercing NonZero<T> to T
1 parent ab2eecc commit e341923

File tree

13 files changed

+341
-1
lines changed

13 files changed

+341
-1
lines changed

‎compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
263263
// It cannot convert closures that require unsafe.
264264
self.coerce_closure_to_fn(a, closure_def_id_a, args_a, b)
265265
}
266+
ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), hir::LangItem::NonZero) => {
267+
self.coerce_non_zero(a, args.type_at(0), b)
268+
}
266269
_ => {
267270
// Otherwise, just use unification rules.
268271
self.unify(a, b)
@@ -827,6 +830,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
827830
self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b))
828831
}
829832

833+
fn coerce_non_zero(
834+
&self,
835+
non_zero: Ty<'tcx>,
836+
wrapped_ty: Ty<'tcx>,
837+
target_ty: Ty<'tcx>,
838+
) -> CoerceResult<'tcx> {
839+
if target_ty.is_ty_var() {
840+
return self.unify(non_zero, target_ty);
841+
}
842+
self.commit_if_ok(|_| self.unify_and(wrapped_ty, target_ty, [], Adjust::NonZeroIntoInner))
843+
.or_else(|_| self.unify(non_zero, target_ty))
844+
}
845+
830846
fn coerce_from_safe_fn(
831847
&self,
832848
fn_ty_a: ty::PolyFnSig<'tcx>,

‎compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
854854
};
855855
self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
856856
}
857+
858+
adjustment::Adjust::NonZeroIntoInner => {}
857859
}
858860
place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?;
859861
}
@@ -1336,6 +1338,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
13361338
adjustment::Adjust::NeverToAny
13371339
| adjustment::Adjust::Pointer(_)
13381340
| adjustment::Adjust::Borrow(_)
1341+
| adjustment::Adjust::NonZeroIntoInner
13391342
| adjustment::Adjust::ReborrowPin(..) => {
13401343
// Result is an rvalue.
13411344
Ok(self.cat_rvalue(expr.hir_id, target))

‎compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
290290
// FIXME(const_trait_impl): We could enforce these; they correspond to
291291
// `&mut T: DerefMut` tho, so it's kinda moot.
292292
}
293-
Adjust::Borrow(_) => {
293+
Adjust::NonZeroIntoInner | Adjust::Borrow(_) => {
294294
// No effects to enforce here.
295295
}
296296
}

‎compiler/rustc_lint/src/autorefs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Muta
171171
| Adjust::Pointer(..)
172172
| Adjust::ReborrowPin(..)
173173
| Adjust::Deref(None)
174+
| Adjust::NonZeroIntoInner
174175
| Adjust::Borrow(AutoBorrow::RawPtr(..)) => None,
175176
}
176177
}

‎compiler/rustc_middle/src/ty/adjustment.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ pub enum Adjust {
105105

106106
/// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`.
107107
ReborrowPin(hir::Mutability),
108+
109+
/// Turn a `NonZero<T>` into `T`
110+
NonZeroIntoInner,
108111
}
109112

110113
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`

‎compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,34 @@ impl<'tcx> ThirBuildCx<'tcx> {
239239
debug!(?kind);
240240
kind
241241
}
242+
Adjust::NonZeroIntoInner => {
243+
// These only happen on `NonZero`
244+
let ty::Adt(adt, args) = expr.ty.kind() else {
245+
span_bug!(span, "nonzero adjustment not based on adt: {expr:#?}")
246+
};
247+
// Find the right field type
248+
let ty = self
249+
.tcx
250+
.type_of(adt.variant(FIRST_VARIANT).fields[FieldIdx::ZERO].did)
251+
.instantiate(self.tcx, args);
252+
// Get rid of the `ZeroablePrimitive` projection
253+
let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
254+
let lhs = self.thir.exprs.push(expr);
255+
ExprKind::Field {
256+
lhs: self.thir.exprs.push(Expr {
257+
span,
258+
temp_lifetime,
259+
ty,
260+
kind: ExprKind::Field {
261+
lhs,
262+
variant_index: FIRST_VARIANT,
263+
name: FieldIdx::ZERO,
264+
},
265+
}),
266+
variant_index: FIRST_VARIANT,
267+
name: FieldIdx::ZERO,
268+
}
269+
}
242270
};
243271

244272
Expr { temp_lifetime, ty: adjustment.target, span, kind }
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ check-pass
2+
3+
use std::num::NonZero;
4+
5+
trait Foo<T>: Sized {
6+
fn bar(self, other: T) {}
7+
}
8+
9+
impl Foo<u8> for u8 {}
10+
impl Foo<u16> for u16 {}
11+
12+
trait Bar {}
13+
impl Bar for u8 {}
14+
impl Bar for u16 {}
15+
fn foo(_: impl Bar) {}
16+
17+
fn main() {
18+
// Check that we can coerce
19+
let x = NonZero::new(5_u8).unwrap();
20+
let y: u8 = x;
21+
22+
// Can coerce by looking at the trait
23+
let x = NonZero::new(5_u8).unwrap();
24+
5_u8.bar(x);
25+
26+
// Check that we can infer the nonzero wrapped type through the coercion
27+
let a = NonZero::new(5).unwrap();
28+
let b: u8 = a;
29+
30+
let a = NonZero::new(5).unwrap();
31+
5_u8.bar(a);
32+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use std::num::NonZero;
2+
3+
trait Foo: Sized {
4+
fn foo(&self) {}
5+
fn bar(self) {}
6+
}
7+
8+
impl Foo for u8 {}
9+
impl Foo for u16 {}
10+
11+
fn foo(_: impl Foo) {}
12+
13+
fn main() {
14+
let x = NonZero::new(5_u8).unwrap();
15+
x.foo();
16+
//~^ ERROR: no method named `foo` found for struct `NonZero` in the current scope
17+
x.bar();
18+
//~^ ERROR: no method named `bar` found for struct `NonZero` in the current scope
19+
foo(x);
20+
//~^ ERROR: the trait bound `NonZero<u8>: Foo` is not satisfied
21+
foo(x as _);
22+
23+
let a = NonZero::new(5).unwrap();
24+
a.foo();
25+
//~^ ERROR: no method named `foo` found for struct `NonZero` in the current scope
26+
a.bar();
27+
//~^ ERROR: no method named `bar` found for struct `NonZero` in the current scope
28+
foo(a);
29+
//~^ ERROR: the trait bound `NonZero<{integer}>: Foo` is not satisfied
30+
foo(a as _);
31+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
error[E0599]: no method named `foo` found for struct `NonZero` in the current scope
2+
--> $DIR/non_zero_coerce_fail.rs:15:7
3+
|
4+
LL | x.foo();
5+
| ^^^ method not found in `NonZero<u8>`
6+
|
7+
= help: items from traits can only be used if the trait is implemented and in scope
8+
note: `Foo` defines an item `foo`, perhaps you need to implement it
9+
--> $DIR/non_zero_coerce_fail.rs:3:1
10+
|
11+
LL | trait Foo: Sized {
12+
| ^^^^^^^^^^^^^^^^
13+
14+
error[E0599]: no method named `bar` found for struct `NonZero` in the current scope
15+
--> $DIR/non_zero_coerce_fail.rs:17:7
16+
|
17+
LL | x.bar();
18+
| ^^^ method not found in `NonZero<u8>`
19+
|
20+
= help: items from traits can only be used if the trait is implemented and in scope
21+
note: `Foo` defines an item `bar`, perhaps you need to implement it
22+
--> $DIR/non_zero_coerce_fail.rs:3:1
23+
|
24+
LL | trait Foo: Sized {
25+
| ^^^^^^^^^^^^^^^^
26+
27+
error[E0277]: the trait bound `NonZero<u8>: Foo` is not satisfied
28+
--> $DIR/non_zero_coerce_fail.rs:19:9
29+
|
30+
LL | foo(x);
31+
| --- ^ the trait `Foo` is not implemented for `NonZero<u8>`
32+
| |
33+
| required by a bound introduced by this call
34+
|
35+
= help: the following other types implement trait `Foo`:
36+
u16
37+
u8
38+
note: required by a bound in `foo`
39+
--> $DIR/non_zero_coerce_fail.rs:11:16
40+
|
41+
LL | fn foo(_: impl Foo) {}
42+
| ^^^ required by this bound in `foo`
43+
44+
error[E0599]: no method named `foo` found for struct `NonZero` in the current scope
45+
--> $DIR/non_zero_coerce_fail.rs:24:7
46+
|
47+
LL | a.foo();
48+
| ^^^ method not found in `NonZero<{integer}>`
49+
|
50+
= help: items from traits can only be used if the trait is implemented and in scope
51+
note: `Foo` defines an item `foo`, perhaps you need to implement it
52+
--> $DIR/non_zero_coerce_fail.rs:3:1
53+
|
54+
LL | trait Foo: Sized {
55+
| ^^^^^^^^^^^^^^^^
56+
57+
error[E0599]: no method named `bar` found for struct `NonZero` in the current scope
58+
--> $DIR/non_zero_coerce_fail.rs:26:7
59+
|
60+
LL | a.bar();
61+
| ^^^ method not found in `NonZero<{integer}>`
62+
|
63+
= help: items from traits can only be used if the trait is implemented and in scope
64+
note: `Foo` defines an item `bar`, perhaps you need to implement it
65+
--> $DIR/non_zero_coerce_fail.rs:3:1
66+
|
67+
LL | trait Foo: Sized {
68+
| ^^^^^^^^^^^^^^^^
69+
70+
error[E0277]: the trait bound `NonZero<{integer}>: Foo` is not satisfied
71+
--> $DIR/non_zero_coerce_fail.rs:28:9
72+
|
73+
LL | foo(a);
74+
| --- ^ the trait `Foo` is not implemented for `NonZero<{integer}>`
75+
| |
76+
| required by a bound introduced by this call
77+
|
78+
= help: the following other types implement trait `Foo`:
79+
u16
80+
u8
81+
note: required by a bound in `foo`
82+
--> $DIR/non_zero_coerce_fail.rs:11:16
83+
|
84+
LL | fn foo(_: impl Foo) {}
85+
| ^^^ required by this bound in `foo`
86+
87+
error: aborting due to 6 previous errors
88+
89+
Some errors have detailed explanations: E0277, E0599.
90+
For more information about an error, try `rustc --explain E0277`.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::num::NonZero;
2+
3+
trait Foo<T>: Sized {
4+
fn foo(&self, other: &T) {}
5+
fn bar(self, other: T) {}
6+
}
7+
8+
impl Foo<u8> for u8 {}
9+
impl Foo<u16> for u16 {}
10+
11+
fn main() {
12+
let x = NonZero::new(5_u8).unwrap();
13+
5_u8.foo(&x);
14+
//~^ ERROR: mismatched types
15+
5_u8.bar(x);
16+
5.foo(&x);
17+
//~^ ERROR: the trait bound `{integer}: Foo<NonZero<u8>>` is not satisfied
18+
5.bar(x);
19+
//~^ ERROR: the trait bound `{integer}: Foo<NonZero<u8>>` is not satisfied
20+
21+
let a = NonZero::new(5).unwrap();
22+
5_u8.foo(&a);
23+
//~^ ERROR: mismatched types
24+
5_u8.bar(a);
25+
5.foo(&a);
26+
//~^ ERROR: the trait bound `{integer}: Foo<NonZero<u8>>` is not satisfied
27+
5.bar(a);
28+
//~^ ERROR: the trait bound `{integer}: Foo<NonZero<u8>>` is not satisfied
29+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /