@@ -126,12 +126,16 @@ fn check_well_founded_typ(
126126pub ( crate ) enum TypNode {
127127 Datatype ( Path ) ,
128128 TraitImpl ( Path ) ,
129+ // This is used to replace an X --> Y edge with X --> SpanInfo --> Y edges
130+ // to give more precise span information than X or Y alone provide
131+ SpanInfo { span_infos_index : usize , text : String } ,
129132}
130133
131134struct CheckPositiveGlobal {
132135 krate : Krate ,
133136 datatypes : HashMap < Path , Datatype > ,
134137 type_graph : Graph < TypNode > ,
138+ span_infos : Vec < Span > ,
135139}
136140
137141struct CheckPositiveLocal {
@@ -140,6 +144,18 @@ struct CheckPositiveLocal {
140144 tparams : HashMap < Ident , AcceptRecursiveType > ,
141145}
142146
147+ pub ( crate ) fn new_span_info_node ( span_infos : & mut Vec < Span > , span : Span , text : String ) -> Node {
148+ let node = Node :: SpanInfo { span_infos_index : span_infos. len ( ) , text } ;
149+ span_infos. push ( span) ;
150+ node
151+ }
152+
153+ fn new_span_info_typ_node ( span_infos : & mut Vec < Span > , span : Span , text : String ) -> TypNode {
154+ let node = TypNode :: SpanInfo { span_infos_index : span_infos. len ( ) , text } ;
155+ span_infos. push ( span) ;
156+ node
157+ }
158+
143159// polarity = Some(true) for positive, Some(false) for negative, None for neither
144160fn check_positive_uses (
145161 global : & CheckPositiveGlobal ,
@@ -208,7 +224,12 @@ fn check_positive_uses(
208224 if global. type_graph . in_same_scc ( & impl_node, & my_node) {
209225 let scc_rep = global. type_graph . get_scc_rep ( & my_node) ;
210226 let scc_nodes = global. type_graph . shortest_cycle_back_to_self ( & scc_rep) ;
211- return Err ( type_scc_error ( & global. krate , & my_node, & scc_nodes) ) ;
227+ return Err ( type_scc_error (
228+ & global. krate ,
229+ & global. span_infos ,
230+ & my_node,
231+ & scc_nodes,
232+ ) ) ;
212233 }
213234 }
214235 Ok ( ( ) )
@@ -256,7 +277,7 @@ fn add_one_type_to_graph(type_graph: &mut Graph<TypNode>, src: &TypNode, typ: &T
256277 }
257278}
258279
259- pub ( crate ) fn build_datatype_graph ( krate : & Krate ) -> Graph < TypNode > {
280+ pub ( crate ) fn build_datatype_graph ( krate : & Krate , span_infos : & mut Vec < Span > ) -> Graph < TypNode > {
260281 let mut type_graph: Graph < TypNode > = Graph :: new ( ) ;
261282
262283 // If datatype D1 has a field whose type mentions datatype D2, create a graph edge D1 --> D2
@@ -270,7 +291,15 @@ pub(crate) fn build_datatype_graph(krate: &Krate) -> Graph<TypNode> {
270291 }
271292
272293 for a in & krate. assoc_type_impls {
273- let src = TypNode :: TraitImpl ( a. x . impl_path . clone ( ) ) ;
294+ let trait_impl_src = TypNode :: TraitImpl ( a. x . impl_path . clone ( ) ) ;
295+ let src = new_span_info_typ_node (
296+ span_infos,
297+ a. span . clone ( ) ,
298+ ": associated type definition, which may depend on other trait implementations \
299+ to satisfy type bounds"
300+ . to_string ( ) ,
301+ ) ;
302+ type_graph. add_edge ( trait_impl_src, src. clone ( ) ) ;
274303 for impl_path in a. x . impl_paths . iter ( ) {
275304 let dst = TypNode :: TraitImpl ( impl_path. clone ( ) ) ;
276305 type_graph. add_edge ( src. clone ( ) , dst) ;
@@ -284,19 +313,21 @@ pub(crate) fn build_datatype_graph(krate: &Krate) -> Graph<TypNode> {
284313 }
285314
286315 type_graph. compute_sccs ( ) ;
287- return type_graph;
316+
317+ type_graph
288318}
289319
290320pub ( crate ) fn check_recursive_types ( krate : & Krate ) -> Result < ( ) , VirErr > {
291- let type_graph = build_datatype_graph ( krate) ;
321+ let mut span_infos: Vec < Span > = Vec :: new ( ) ;
322+ let type_graph = build_datatype_graph ( krate, & mut span_infos) ;
292323 let mut datatypes: HashMap < Path , Datatype > = HashMap :: new ( ) ;
293324 let mut datatypes_well_founded: HashSet < Path > = HashSet :: new ( ) ;
294325
295326 for datatype in & krate. datatypes {
296327 datatypes. insert ( datatype. x . path . clone ( ) , datatype. clone ( ) ) ;
297328 }
298329
299- let global = CheckPositiveGlobal { krate : krate. clone ( ) , datatypes, type_graph } ;
330+ let global = CheckPositiveGlobal { krate : krate. clone ( ) , datatypes, type_graph, span_infos } ;
300331
301332 for function in & krate. functions {
302333 if let FunctionKind :: TraitMethodDecl { .. } = function. x . kind {
@@ -343,6 +374,7 @@ pub(crate) fn check_recursive_types(krate: &Krate) -> Result<(), VirErr> {
343374 TypNode :: TraitImpl ( _) if global. type_graph . node_is_in_cycle ( node) => {
344375 return Err ( type_scc_error (
345376 krate,
377+ & global. span_infos ,
346378 node,
347379 & global. type_graph . shortest_cycle_back_to_self ( scc) ,
348380 ) ) ;
@@ -377,75 +409,96 @@ pub(crate) fn check_recursive_types(krate: &Krate) -> Result<(), VirErr> {
377409 Ok ( ( ) )
378410}
379411
380- fn type_scc_error ( krate : & Krate , head : & TypNode , nodes : & Vec < TypNode > ) -> VirErr {
412+ fn type_scc_error (
413+ krate : & Krate ,
414+ span_infos : & Vec < Span > ,
415+ head : & TypNode ,
416+ nodes : & Vec < TypNode > ,
417+ ) -> VirErr {
381418 let msg =
382419 "found a cyclic self-reference in a trait definition, which may result in nontermination"
383420 . to_string ( ) ;
384421 let mut err = crate :: messages:: error_bare ( msg) ;
385422 for ( i, node) in nodes. iter ( ) . enumerate ( ) {
386- let mut push = |node : & TypNode , span : Span | {
423+ let mut push = |node : & TypNode , span : Span , text : & str | {
387424 if node == head {
388425 err = err. primary_span ( & span) ;
389426 }
390- let msg = format ! ( "may be part of cycle (node {} of {} in cycle)" , i + 1 , nodes. len( ) ) ;
427+ let msg = format ! (
428+ "may be part of cycle (node {} of {} in cycle){}" ,
429+ i + 1 ,
430+ nodes. len( ) ,
431+ text
432+ ) ;
391433 err = err. secondary_label ( & span, msg) ;
392434 } ;
393435 match node {
394436 TypNode :: Datatype ( path) => {
395437 if let Some ( d) = krate. datatypes . iter ( ) . find ( |t| t. x . path == * path) {
396438 let span = d. span . clone ( ) ;
397- push ( node, span) ;
439+ push ( node, span, ": type definition" ) ;
398440 }
399441 }
400442 TypNode :: TraitImpl ( impl_path) => {
401443 if let Some ( t) = krate. trait_impls . iter ( ) . find ( |t| t. x . impl_path == * impl_path) {
402444 let span = t. span . clone ( ) ;
403- push ( node, span) ;
445+ push ( node, span, ": implementation of trait for a type" ) ;
404446 }
405447 }
448+ TypNode :: SpanInfo { span_infos_index, text } => {
449+ push ( node, span_infos[ * span_infos_index] . clone ( ) , text) ;
450+ }
406451 }
407452 }
408453 err
409454}
410455
411- fn scc_error ( krate : & Krate , head : & Node , nodes : & Vec < Node > ) -> VirErr {
456+ fn scc_error ( krate : & Krate , span_infos : & Vec < Span > , head : & Node , nodes : & Vec < Node > ) -> VirErr {
412457 let msg =
413458 "found a cyclic self-reference in a trait definition, which may result in nontermination"
414459 . to_string ( ) ;
415460 let mut err = crate :: messages:: error_bare ( msg) ;
416461 for ( i, node) in nodes. iter ( ) . enumerate ( ) {
417- let mut push = |node : & Node , span : Span | {
462+ let mut push = |node : & Node , span : Span , text : & str | {
418463 if node == head {
419464 err = err. primary_span ( & span) ;
420465 }
421- let msg = format ! ( "may be part of cycle (node {} of {} in cycle)" , i + 1 , nodes. len( ) ) ;
466+ let msg = format ! (
467+ "may be part of cycle (node {} of {} in cycle){}" ,
468+ i + 1 ,
469+ nodes. len( ) ,
470+ text
471+ ) ;
422472 err = err. secondary_label ( & span, msg) ;
423473 } ;
424474 match node {
425475 Node :: Fun ( fun) => {
426476 if let Some ( f) = krate. functions . iter ( ) . find ( |f| f. x . name == * fun) {
427477 let span = f. span . clone ( ) ;
428- push ( node, span) ;
478+ push ( node, span, ": function definition, whose body may have dependencies" ) ;
429479 }
430480 }
431481 Node :: Datatype ( path) => {
432482 if let Some ( d) = krate. datatypes . iter ( ) . find ( |t| t. x . path == * path) {
433483 let span = d. span . clone ( ) ;
434- push ( node, span) ;
484+ push ( node, span, ": type definition" ) ;
435485 }
436486 }
437487 Node :: Trait ( trait_path) => {
438488 if let Some ( t) = krate. traits . iter ( ) . find ( |t| t. x . name == * trait_path) {
439489 let span = t. span . clone ( ) ;
440- push ( node, span) ;
490+ push ( node, span, ": declaration of trait" ) ;
441491 }
442492 }
443493 Node :: TraitImpl ( impl_path) => {
444494 if let Some ( t) = krate. trait_impls . iter ( ) . find ( |t| t. x . impl_path == * impl_path) {
445495 let span = t. span . clone ( ) ;
446- push ( node, span) ;
496+ push ( node, span, ": implementation of trait for a type" ) ;
447497 }
448498 }
499+ Node :: SpanInfo { span_infos_index, text } => {
500+ push ( node, span_infos[ * span_infos_index] . clone ( ) , text) ;
501+ }
449502 }
450503 }
451504 err
@@ -495,14 +548,27 @@ pub(crate) fn add_trait_to_graph(call_graph: &mut Graph<Node>, trt: &Trait) {
495548 }
496549}
497550
498- pub ( crate ) fn add_trait_impl_to_graph ( call_graph : & mut Graph < Node > , t : & crate :: ast:: TraitImpl ) {
551+ pub ( crate ) fn add_trait_impl_to_graph (
552+ span_infos : & mut Vec < Span > ,
553+ call_graph : & mut Graph < Node > ,
554+ t : & crate :: ast:: TraitImpl ,
555+ ) {
499556 // For
500557 // trait T<...> where ...: U1(...), ..., ...: Un(...)
501558 // impl T<t1...tn> for ... { ... }
502559 // Add necessary impl_T_for_* --> impl_Ui_for_* edges
503560 // This corresponds to instantiating the a: Dictionary_U<A> field in the comments below
504- let src_node = Node :: TraitImpl ( t. x . impl_path . clone ( ) ) ;
505- for imp in t. x . trait_typ_arg_impls . iter ( ) {
561+ let trait_impl_src_node = Node :: TraitImpl ( t. x . impl_path . clone ( ) ) ;
562+ let src_node = new_span_info_node (
563+ span_infos,
564+ t. x . trait_typ_arg_impls . span . clone ( ) ,
565+ ": an implementation of a trait, applying the trait to some type arguments, \
566+ for some `Self` type, where applying the trait to type arguments and declaring \
567+ the `Self` type may depend on other trait implementations to satisfy type bounds"
568+ . to_string ( ) ,
569+ ) ;
570+ call_graph. add_edge ( trait_impl_src_node, src_node. clone ( ) ) ;
571+ for imp in t. x . trait_typ_arg_impls . x . iter ( ) {
506572 if & t. x . impl_path != imp {
507573 call_graph. add_edge ( src_node. clone ( ) , Node :: TraitImpl ( imp. clone ( ) ) ) ;
508574 }
@@ -648,6 +714,7 @@ pub fn check_traits(krate: &Krate, ctx: &GlobalCtx) -> Result<(), VirErr> {
648714 _ if ctx. func_call_graph . node_is_in_cycle ( node) => {
649715 return Err ( scc_error (
650716 krate,
717+ & ctx. datatype_graph_span_infos ,
651718 node,
652719 & ctx. func_call_graph . shortest_cycle_back_to_self ( node) ,
653720 ) ) ;
0 commit comments