@@ -2,6 +2,7 @@ use either::Either;
22use hir:: { known, Callable , HasVisibility , HirDisplay , Semantics , TypeInfo } ;
33use ide_db:: RootDatabase ;
44use ide_db:: { base_db:: FileRange , helpers:: FamousDefs } ;
5+ use itertools:: Itertools ;
56use stdx:: to_lower_snake_case;
67use syntax:: {
78 ast:: { self , AstNode , HasArgList , HasName } ,
@@ -198,28 +199,95 @@ fn get_bind_pat_hints(
198199
199200 let descended = sema. descend_node_into_attributes ( pat. clone ( ) ) . pop ( ) ;
200201 let desc_pat = descended. as_ref ( ) . unwrap_or ( pat) ;
201- let krate = sema. scope ( desc_pat. syntax ( ) ) . module ( ) . map ( |it| it. krate ( ) ) ;
202- let famous_defs = FamousDefs ( sema, krate) ;
203-
204202 let ty = sema. type_of_pat ( & desc_pat. clone ( ) . into ( ) ) ?. original ;
205203
206204 if should_not_display_type_hint ( sema, & pat, & ty) {
207205 return None ;
208206 }
209207
208+ let krate = sema. scope ( desc_pat. syntax ( ) ) . module ( ) . map ( |it| it. krate ( ) ) ;
209+ let famous_defs = FamousDefs ( sema, krate) ;
210+ let label = hint_iterator ( sema, & famous_defs, config, & ty) ;
211+
212+ let label = match label {
213+ Some ( label) => label,
214+ None => {
215+ let ty_name = ty. display_truncated ( sema. db , config. max_length ) . to_string ( ) ;
216+ if is_named_constructor ( sema, pat, & ty_name) . is_some ( ) {
217+ return None ;
218+ }
219+ ty_name. into ( )
220+ }
221+ } ;
222+
210223 acc. push ( InlayHint {
211224 range : match pat. name ( ) {
212225 Some ( name) => name. syntax ( ) . text_range ( ) ,
213226 None => pat. syntax ( ) . text_range ( ) ,
214227 } ,
215228 kind : InlayKind :: TypeHint ,
216- label : hint_iterator ( sema, & famous_defs, config, & ty)
217- . unwrap_or_else ( || ty. display_truncated ( sema. db , config. max_length ) . to_string ( ) . into ( ) ) ,
229+ label,
218230 } ) ;
219231
220232 Some ( ( ) )
221233}
222234
235+ fn is_named_constructor (
236+ sema : & Semantics < RootDatabase > ,
237+ pat : & ast:: IdentPat ,
238+ ty_name : & str ,
239+ ) -> Option < ( ) > {
240+ let let_node = pat. syntax ( ) . parent ( ) ?;
241+ let expr = match_ast ! {
242+ match let_node {
243+ ast:: LetStmt ( it) => it. initializer( ) ,
244+ ast:: Condition ( it) => it. expr( ) ,
245+ _ => None ,
246+ }
247+ } ?;
248+
249+ let expr = sema. descend_node_into_attributes ( expr. clone ( ) ) . pop ( ) . unwrap_or ( expr) ;
250+ // unwrap postfix expressions
251+ let expr = match expr {
252+ ast:: Expr :: TryExpr ( it) => it. expr ( ) ,
253+ ast:: Expr :: AwaitExpr ( it) => it. expr ( ) ,
254+ expr => Some ( expr) ,
255+ } ?;
256+ let expr = match expr {
257+ ast:: Expr :: CallExpr ( call) => match call. expr ( ) ? {
258+ ast:: Expr :: PathExpr ( p) => p,
259+ _ => return None ,
260+ } ,
261+ _ => return None ,
262+ } ;
263+ let path = expr. path ( ) ?;
264+
265+ // Check for tuple-struct or tuple-variant in which case we can check the last segment
266+ let callable = sema. type_of_expr ( & ast:: Expr :: PathExpr ( expr) ) ?. original . as_callable ( sema. db ) ;
267+ let callable_kind = callable. map ( |it| it. kind ( ) ) ;
268+ if let Some ( hir:: CallableKind :: TupleStruct ( _) | hir:: CallableKind :: TupleEnumVariant ( _) ) =
269+ callable_kind
270+ {
271+ if let Some ( ctor) = path. segment ( ) {
272+ return ( & ctor. to_string ( ) == ty_name) . then ( || ( ) ) ;
273+ }
274+ }
275+
276+ // otherwise use the qualifying segment as the constructor name
277+ let qual_seg = path. qualifier ( ) ?. segment ( ) ?;
278+ let ctor_name = match qual_seg. kind ( ) ? {
279+ ast:: PathSegmentKind :: Name ( name_ref) => {
280+ match qual_seg. generic_arg_list ( ) . map ( |it| it. generic_args ( ) ) {
281+ Some ( generics) => format ! ( "{}<{}>" , name_ref, generics. format( ", " ) ) ,
282+ None => name_ref. to_string ( ) ,
283+ }
284+ }
285+ ast:: PathSegmentKind :: Type { type_ref : Some ( ty) , trait_ref : None } => ty. to_string ( ) ,
286+ _ => return None ,
287+ } ;
288+ ( & ctor_name == ty_name) . then ( || ( ) )
289+ }
290+
223291/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
224292fn hint_iterator (
225293 sema : & Semantics < RootDatabase > ,
@@ -470,10 +538,12 @@ mod tests {
470538 max_length : None ,
471539 } ;
472540
541+ #[ track_caller]
473542 fn check ( ra_fixture : & str ) {
474543 check_with_config ( TEST_CONFIG , ra_fixture) ;
475544 }
476545
546+ #[ track_caller]
477547 fn check_params ( ra_fixture : & str ) {
478548 check_with_config (
479549 InlayHintsConfig {
@@ -486,6 +556,7 @@ mod tests {
486556 ) ;
487557 }
488558
559+ #[ track_caller]
489560 fn check_types ( ra_fixture : & str ) {
490561 check_with_config (
491562 InlayHintsConfig {
@@ -498,6 +569,7 @@ mod tests {
498569 ) ;
499570 }
500571
572+ #[ track_caller]
501573 fn check_chains ( ra_fixture : & str ) {
502574 check_with_config (
503575 InlayHintsConfig {
@@ -510,6 +582,7 @@ mod tests {
510582 ) ;
511583 }
512584
585+ #[ track_caller]
513586 fn check_with_config ( config : InlayHintsConfig , ra_fixture : & str ) {
514587 let ( analysis, file_id) = fixture:: file ( & ra_fixture) ;
515588 let expected = extract_annotations ( & * analysis. file_text ( file_id) . unwrap ( ) ) ;
@@ -519,6 +592,7 @@ mod tests {
519592 assert_eq ! ( expected, actual, "\n Expected:\n {:#?}\n \n Actual:\n {:#?}" , expected, actual) ;
520593 }
521594
595+ #[ track_caller]
522596 fn check_expect ( config : InlayHintsConfig , ra_fixture : & str , expect : Expect ) {
523597 let ( analysis, file_id) = fixture:: file ( & ra_fixture) ;
524598 let inlay_hints = analysis. inlay_hints ( & config, file_id) . unwrap ( ) ;
@@ -1191,11 +1265,12 @@ trait Display {}
11911265trait Sync {}
11921266
11931267fn main() {
1194- let _v = Vec::<Box<&(dyn Display + Sync)>>::new();
1268+ // The block expression wrapping disables the constructor hint hiding logic
1269+ let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
11951270 //^^ Vec<Box<&(dyn Display + Sync)>>
1196- let _v = Vec::<Box<*const (dyn Display + Sync)>>::new();
1271+ let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() } ;
11971272 //^^ Vec<Box<*const (dyn Display + Sync)>>
1198- let _v = Vec::<Box<dyn Display + Sync>>::new();
1273+ let _v = { Vec::<Box<dyn Display + Sync>>::new() } ;
11991274 //^^ Vec<Box<dyn Display + Sync>>
12001275}
12011276"# ,
@@ -1234,6 +1309,48 @@ fn main() {
12341309 ) ;
12351310 }
12361311
1312+ #[ test]
1313+ fn skip_constructor_type_hints ( ) {
1314+ check_types (
1315+ r#"
1316+ //- minicore: try
1317+ use core::ops::ControlFlow;
1318+
1319+ struct Struct;
1320+ struct TupleStruct();
1321+
1322+ impl Struct {
1323+ fn new() -> Self {
1324+ Struct
1325+ }
1326+ fn try_new() -> ControlFlow<(), Self> {
1327+ ControlFlow::Continue(Struct)
1328+ }
1329+ }
1330+
1331+ struct Generic<T>(T);
1332+ impl Generic<i32> {
1333+ fn new() -> Self {
1334+ Generic(0)
1335+ }
1336+ }
1337+
1338+ fn main() {
1339+ let strukt = Struct::new();
1340+ let tuple_struct = TupleStruct();
1341+ let generic0 = Generic::new();
1342+ // ^^^^^^^^ Generic<i32>
1343+ let generic1 = Generic::<i32>::new();
1344+ let generic2 = <Generic<i32>>::new();
1345+ }
1346+
1347+ fn fallible() -> ControlFlow<()> {
1348+ let strukt = Struct::try_new()?;
1349+ }
1350+ "# ,
1351+ ) ;
1352+ }
1353+
12371354 #[ test]
12381355 fn closures ( ) {
12391356 check (
0 commit comments