@@ -11,13 +11,20 @@ use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
11
11
use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
12
12
use rustc_span:: symbol:: { sym, Ident } ;
13
13
use rustc_span:: { Span , Symbol } ;
14
- use smallvec:: { smallvec, SmallVec } ;
15
14
use thin_vec:: { thin_vec, ThinVec } ;
16
15
17
16
macro_rules! path {
18
17
( $span: expr, $( $part: ident) ::* ) => { vec![ $( Ident :: new( sym:: $part, $span) , ) * ] }
19
18
}
20
19
20
+ enum PointeeChoice {
21
+ None ,
22
+ Exactly ( usize , Span ) ,
23
+ Assumed ( usize ) ,
24
+ Ambiguous ,
25
+ MultiplePointeeChoice ( Span , Span ) ,
26
+ }
27
+
21
28
pub fn expand_deriving_smart_ptr (
22
29
cx : & ExtCtxt < ' _ > ,
23
30
span : Span ,
@@ -68,8 +75,7 @@ pub fn expand_deriving_smart_ptr(
68
75
} ;
69
76
70
77
// Convert generic parameters (from the struct) into generic args.
71
- let mut pointee_param = None ;
72
- let mut multiple_pointee_diag: SmallVec < [ _ ; 2 ] > = smallvec ! [ ] ;
78
+ let mut pointee_param = PointeeChoice :: None ;
73
79
let self_params = generics
74
80
. params
75
81
. iter ( )
@@ -78,33 +84,59 @@ pub fn expand_deriving_smart_ptr(
78
84
GenericParamKind :: Lifetime => GenericArg :: Lifetime ( cx. lifetime ( p. span ( ) , p. ident ) ) ,
79
85
GenericParamKind :: Type { .. } => {
80
86
if p. attrs ( ) . iter ( ) . any ( |attr| attr. has_name ( sym:: pointee) ) {
81
- if pointee_param. is_some ( ) {
82
- multiple_pointee_diag. push ( cx. dcx ( ) . struct_span_err (
83
- p. span ( ) ,
84
- "`SmartPointer` can only admit one type as pointee" ,
85
- ) ) ;
86
- } else {
87
- pointee_param = Some ( idx) ;
87
+ match pointee_param {
88
+ PointeeChoice :: Assumed ( _)
89
+ | PointeeChoice :: Ambiguous
90
+ | PointeeChoice :: None => {
91
+ pointee_param = PointeeChoice :: Exactly ( idx, p. span ( ) )
92
+ }
93
+ PointeeChoice :: Exactly ( _, another) => {
94
+ pointee_param = PointeeChoice :: MultiplePointeeChoice ( another, p. span ( ) )
95
+ }
96
+ PointeeChoice :: MultiplePointeeChoice ( _, _) => { }
97
+ }
98
+ } else {
99
+ match pointee_param {
100
+ PointeeChoice :: None => pointee_param = PointeeChoice :: Assumed ( idx) ,
101
+ PointeeChoice :: Assumed ( _) | PointeeChoice :: Ambiguous => {
102
+ pointee_param = PointeeChoice :: Ambiguous
103
+ }
104
+ PointeeChoice :: Exactly ( _, _)
105
+ | PointeeChoice :: MultiplePointeeChoice ( _, _) => { }
88
106
}
89
107
}
90
108
GenericArg :: Type ( cx. ty_ident ( p. span ( ) , p. ident ) )
91
109
}
92
110
GenericParamKind :: Const { .. } => GenericArg :: Const ( cx. const_ident ( p. span ( ) , p. ident ) ) ,
93
111
} )
94
112
. collect :: < Vec < _ > > ( ) ;
95
- let Some ( pointee_param_idx) = pointee_param else {
96
- cx. dcx ( ) . struct_span_err (
97
- span,
98
- "At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits" ,
99
- ) . emit ( ) ;
100
- return ;
101
- } ;
102
- if !multiple_pointee_diag. is_empty ( ) {
103
- for diag in multiple_pointee_diag {
104
- diag. emit ( ) ;
113
+ let pointee_param_idx = match pointee_param {
114
+ PointeeChoice :: Assumed ( idx) | PointeeChoice :: Exactly ( idx, _) => idx,
115
+ PointeeChoice :: None => {
116
+ cx. dcx ( ) . struct_span_err (
117
+ span,
118
+ "`SmartPointer` can only be derived on `struct`s that are generic over at least one type" ,
119
+ ) . emit ( ) ;
120
+ return ;
105
121
}
106
- return ;
107
- }
122
+ PointeeChoice :: Ambiguous => {
123
+ cx. dcx ( ) . struct_span_err (
124
+ span,
125
+ "Exactly one generic parameters when there are at least two generic type parameters \
126
+ should be designated as `#[pointee]` in order to derive `SmartPointer` traits",
127
+ ) . emit ( ) ;
128
+ return ;
129
+ }
130
+ PointeeChoice :: MultiplePointeeChoice ( one, another) => {
131
+ cx. dcx ( )
132
+ . struct_span_err (
133
+ vec ! [ one, another] ,
134
+ "`SmartPointer` can only admit one type as pointee" ,
135
+ )
136
+ . emit ( ) ;
137
+ return ;
138
+ }
139
+ } ;
108
140
109
141
// Create the type of `self`.
110
142
let path = cx. path_all ( span, false , vec ! [ name_ident] , self_params. clone ( ) ) ;
0 commit comments