oso-oso 0.23.0 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,7 @@ module Oso
6
6
  module Polar
7
7
  module FFI
8
8
  # Wrapper class for Polar FFI pointer + operations.
9
- class Polar < ::FFI::AutoPointer
9
+ class Polar < ::FFI::AutoPointer # rubocop:disable Metrics/ClassLength
10
10
  attr_accessor :enrich_message
11
11
 
12
12
  Rust = Module.new do
@@ -14,21 +14,28 @@ module Oso
14
14
  ffi_lib FFI::LIB_PATH
15
15
 
16
16
  attach_function :new, :polar_new, [], FFI::Polar
17
- attach_function :load, :polar_load, [FFI::Polar, :string], :int32
18
- attach_function :clear_rules, :polar_clear_rules, [FFI::Polar], :int32
17
+ attach_function :load, :polar_load, [FFI::Polar, :string], CResultVoid
18
+ attach_function :clear_rules, :polar_clear_rules, [FFI::Polar], CResultVoid
19
19
  attach_function :next_inline_query, :polar_next_inline_query, [FFI::Polar, :uint32], FFI::Query
20
20
  attach_function :new_id, :polar_get_external_id, [FFI::Polar], :uint64
21
- attach_function :new_query_from_str, :polar_new_query, [FFI::Polar, :string, :uint32], FFI::Query
22
- attach_function :new_query_from_term, :polar_new_query_from_term, [FFI::Polar, :string, :uint32], FFI::Query
23
- attach_function :register_constant, :polar_register_constant, [FFI::Polar, :string, :string], :int32
24
- attach_function :register_mro, :polar_register_mro, [FFI::Polar, :string, :string], :int32
25
- attach_function :next_message, :polar_next_polar_message, [FFI::Polar], FFI::Message
21
+ attach_function :new_query_from_str, :polar_new_query, [FFI::Polar, :string, :uint32], CResultQuery
22
+ attach_function :new_query_from_term, :polar_new_query_from_term, [FFI::Polar, :string, :uint32], CResultQuery
23
+ attach_function :register_constant, :polar_register_constant, [FFI::Polar, :string, :string], CResultVoid
24
+ attach_function :register_mro, :polar_register_mro, [FFI::Polar, :string, :string], CResultVoid
25
+ attach_function :next_message, :polar_next_polar_message, [FFI::Polar], CResultString
26
26
  attach_function :free, :polar_free, [FFI::Polar], :int32
27
+ attach_function :result_free, :result_free, [:pointer], :int32
27
28
  attach_function(
28
29
  :build_filter_plan,
29
30
  :polar_build_filter_plan,
30
31
  [FFI::Polar, :string, :string, :string, :string],
31
- :string
32
+ CResultString
33
+ )
34
+ attach_function(
35
+ :build_data_filter,
36
+ :polar_build_data_filter,
37
+ [FFI::Polar, :string, :string, :string, :string],
38
+ CResultString
32
39
  )
33
40
  end
34
41
  private_constant :Rust
@@ -36,10 +43,7 @@ module Oso
36
43
  # @return [FFI::Polar]
37
44
  # @raise [FFI::Error] if the FFI call returns an error.
38
45
  def self.create
39
- polar = Rust.new
40
- handle_error if polar.null?
41
-
42
- polar
46
+ Rust.new
43
47
  end
44
48
 
45
49
  def build_filter_plan(types, partials, variable, class_tag)
@@ -47,9 +51,19 @@ module Oso
47
51
  partials = JSON.dump(partials)
48
52
  plan = Rust.build_filter_plan(self, types, partials, variable, class_tag)
49
53
  process_messages
50
- handle_error if plan.nil?
54
+ plan = check_result plan
55
+ # TODO(gw) more error checking?
56
+ JSON.parse plan.to_s
57
+ end
58
+
59
+ def build_data_filter(types, partials, variable, class_tag)
60
+ types = JSON.dump(types)
61
+ partials = JSON.dump(partials)
62
+ plan = Rust.build_data_filter(self, types, partials, variable, class_tag)
63
+ process_messages
64
+ plan = check_result plan
51
65
  # TODO(gw) more error checking?
52
- JSON.parse plan
66
+ JSON.parse plan.to_s
53
67
  end
54
68
 
55
69
  # @param sources [Array<Source>]
@@ -57,14 +71,14 @@ module Oso
57
71
  def load(sources)
58
72
  loaded = Rust.load(self, JSON.dump(sources))
59
73
  process_messages
60
- handle_error if loaded.zero?
74
+ check_result loaded
61
75
  end
62
76
 
63
77
  # @raise [FFI::Error] if the FFI call returns an error.
64
78
  def clear_rules
65
79
  cleared = Rust.clear_rules(self)
66
80
  process_messages
67
- handle_error if cleared.zero?
81
+ check_result cleared
68
82
  end
69
83
 
70
84
  # @return [FFI::Query] if there are remaining inline queries.
@@ -79,12 +93,7 @@ module Oso
79
93
  # @return [Integer]
80
94
  # @raise [FFI::Error] if the FFI call returns an error.
81
95
  def new_id
82
- id = Rust.new_id(self)
83
- # TODO(gj): I don't think this error check is correct. If getting a new ID fails on the
84
- # Rust side, it'll probably surface as a panic (e.g., the KB lock is poisoned).
85
- handle_error if id.zero?
86
-
87
- id
96
+ Rust.new_id(self)
88
97
  end
89
98
 
90
99
  # @param str [String] Query string.
@@ -93,9 +102,7 @@ module Oso
93
102
  def new_query_from_str(str)
94
103
  query = Rust.new_query_from_str(self, str, 0)
95
104
  process_messages
96
- handle_error if query.null?
97
-
98
- query
105
+ check_result query
99
106
  end
100
107
 
101
108
  # @param term [Hash<String, Object>]
@@ -104,9 +111,7 @@ module Oso
104
111
  def new_query_from_term(term)
105
112
  query = Rust.new_query_from_term(self, JSON.dump(term), 0)
106
113
  process_messages
107
- handle_error if query.null?
108
-
109
- query
114
+ check_result query
110
115
  end
111
116
 
112
117
  # @param name [String]
@@ -114,7 +119,7 @@ module Oso
114
119
  # @raise [FFI::Error] if the FFI call returns an error.
115
120
  def register_constant(value, name:)
116
121
  registered = Rust.register_constant(self, name, JSON.dump(value))
117
- handle_error if registered.zero?
122
+ check_result registered
118
123
  end
119
124
 
120
125
  # @param name [String]
@@ -122,11 +127,24 @@ module Oso
122
127
  # @raise [FFI::Error] if the FFI call returns an error.
123
128
  def register_mro(name, mro)
124
129
  registered = Rust.register_mro(self, name, JSON.dump(mro))
125
- handle_error if registered.zero?
130
+ check_result registered
126
131
  end
127
132
 
128
133
  def next_message
129
- Rust.next_message(self)
134
+ check_result Rust.next_message(self)
135
+ end
136
+
137
+ def process_message(message, enrich_message)
138
+ message = JSON.parse(message.to_s)
139
+ kind = message['kind']
140
+ msg = enrich_message.call(message['msg'])
141
+
142
+ case kind
143
+ when 'Print'
144
+ puts(msg)
145
+ when 'Warning'
146
+ warn(format('[warning] %<msg>s', msg: msg))
147
+ end
130
148
  end
131
149
 
132
150
  def process_messages
@@ -134,12 +152,19 @@ module Oso
134
152
  message = next_message
135
153
  break if message.null?
136
154
 
137
- message.process(enrich_message)
155
+ process_message(message, enrich_message)
138
156
  end
139
157
  end
140
158
 
141
- def handle_error
142
- raise FFI::Error.get(enrich_message)
159
+ def check_result(res)
160
+ result = res[:result]
161
+ error = res[:error]
162
+ Rust.result_free(res)
163
+
164
+ raise 'internal error: both result and error pointers are not null' if !error.null? && !result.zero?
165
+ raise FFI::Error.get(error, enrich_message) unless error.null?
166
+
167
+ result
143
168
  end
144
169
  end
145
170
  end
@@ -13,15 +13,16 @@ module Oso
13
13
  extend ::FFI::Library
14
14
  ffi_lib FFI::LIB_PATH
15
15
 
16
- attach_function :debug_command, :polar_debug_command, [FFI::Query, :string], :int32
17
- attach_function :call_result, :polar_call_result, [FFI::Query, :uint64, :string], :int32
18
- attach_function :question_result, :polar_question_result, [FFI::Query, :uint64, :int32], :int32
19
- attach_function :application_error, :polar_application_error, [FFI::Query, :string], :int32
20
- attach_function :next_event, :polar_next_query_event, [FFI::Query], FFI::QueryEvent
21
- attach_function :next_message, :polar_next_query_message, [FFI::Query], FFI::Message
22
- attach_function :source, :polar_query_source_info, [FFI::Query], FFI::Source
16
+ attach_function :debug_command, :polar_debug_command, [FFI::Query, :string], CResultVoid
17
+ attach_function :call_result, :polar_call_result, [FFI::Query, :uint64, :string], CResultVoid
18
+ attach_function :question_result, :polar_question_result, [FFI::Query, :uint64, :int32], CResultVoid
19
+ attach_function :application_error, :polar_application_error, [FFI::Query, :string], CResultVoid
20
+ attach_function :next_event, :polar_next_query_event, [FFI::Query], CResultString
21
+ attach_function :next_message, :polar_next_query_message, [FFI::Query], CResultString
22
+ attach_function :source, :polar_query_source_info, [FFI::Query], CResultString
23
23
  attach_function :free, :query_free, [FFI::Query], :int32
24
- attach_function :bind, :polar_bind, [FFI::Query, :string, :string], :int32
24
+ attach_function :result_free, :result_free, [:pointer], :int32
25
+ attach_function :bind, :polar_bind, [FFI::Query, :string, :string], CResultVoid
25
26
  end
26
27
  private_constant :Rust
27
28
 
@@ -30,15 +31,15 @@ module Oso
30
31
  def debug_command(cmd)
31
32
  res = Rust.debug_command(self, cmd)
32
33
  process_messages
33
- handle_error if res.zero?
34
+ check_result res
34
35
  end
35
36
 
36
- # @param result [String]
37
+ # @param value [Object]
37
38
  # @param call_id [Integer]
38
39
  # @raise [FFI::Error] if the FFI call returns an error.
39
- def call_result(result, call_id:)
40
- res = Rust.call_result(self, call_id, result)
41
- handle_error if res.zero?
40
+ def call_result(value, call_id:)
41
+ res = Rust.call_result(self, call_id, JSON.dump(value))
42
+ check_result res
42
43
  end
43
44
 
44
45
  # @param result [Boolean]
@@ -47,14 +48,14 @@ module Oso
47
48
  def question_result(result, call_id:)
48
49
  result = result ? 1 : 0
49
50
  res = Rust.question_result(self, call_id, result)
50
- handle_error if res.zero?
51
+ check_result res
51
52
  end
52
53
 
53
54
  # @param message [String]
54
55
  # @raise [FFI::Error] if the FFI call returns an error.
55
56
  def application_error(message)
56
57
  res = Rust.application_error(self, message)
57
- handle_error if res.zero?
58
+ check_result res
58
59
  end
59
60
 
60
61
  # @return [::Oso::Polar::QueryEvent]
@@ -62,18 +63,32 @@ module Oso
62
63
  def next_event
63
64
  event = Rust.next_event(self)
64
65
  process_messages
65
- handle_error if event.null?
66
+ event = check_result event
66
67
 
67
68
  ::Oso::Polar::QueryEvent.new(JSON.parse(event.to_s))
68
69
  end
69
70
 
70
71
  def bind(name, value)
71
72
  res = Rust.bind(self, name, JSON.dump(value))
72
- handle_error if res.zero?
73
+ check_result res
73
74
  end
74
75
 
75
76
  def next_message
76
- Rust.next_message(self)
77
+ check_result Rust.next_message(self)
78
+ end
79
+
80
+ def process_message(message, enrich_message)
81
+ message = JSON.parse(message.to_s)
82
+ kind = message['kind']
83
+ msg = message['msg']
84
+ msg = enrich_message.call(msg)
85
+
86
+ case kind
87
+ when 'Print'
88
+ puts(msg)
89
+ when 'Warning'
90
+ warn(format('[warning] %<msg>s', msg: msg))
91
+ end
77
92
  end
78
93
 
79
94
  def process_messages
@@ -81,7 +96,7 @@ module Oso
81
96
  message = next_message
82
97
  break if message.null?
83
98
 
84
- message.process(enrich_message)
99
+ process_message(message, enrich_message)
85
100
  end
86
101
  end
87
102
 
@@ -89,13 +104,24 @@ module Oso
89
104
  # @raise [FFI::Error] if the FFI call returns an error.
90
105
  def source
91
106
  res = Rust.source(self)
92
- handle_error if res.null?
107
+ res = check_result res
93
108
 
94
109
  res.to_s
95
110
  end
96
111
 
97
- def handle_error
98
- raise FFI::Error.get(enrich_message)
112
+ # Unwrap the result by (a) extracting the pointers for
113
+ # result and error, (b) freeing the result pointers, and then
114
+ # (c) either returning the result pointer, or constructing and
115
+ # raising the error.
116
+ def check_result(res)
117
+ result = res[:result]
118
+ error = res[:error]
119
+ Rust.result_free(res)
120
+
121
+ raise 'internal error: both result and error pointers are not null' if !error.null? && !result.zero?
122
+ raise FFI::Error.get(error, enrich_message) unless error.null?
123
+
124
+ result
99
125
  end
100
126
  end
101
127
  end
@@ -1,10 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module Oso
4
6
  module Polar
5
7
  module FFI
6
- # Wrapper class for Source FFI pointer.
7
- class Source < ::FFI::AutoPointer
8
+ # Wrapper class for Rust strings.
9
+ #
10
+ # Since we force all strings to go through this
11
+ # the `AutoPointer` class will handle
12
+ # actually freeing the string when deleting it
13
+ class RustString < ::FFI::AutoPointer
8
14
  # @return [String]
9
15
  def to_s
10
16
  @to_s ||= read_string.force_encoding('UTF-8')
@@ -14,7 +20,7 @@ module Oso
14
20
  extend ::FFI::Library
15
21
  ffi_lib FFI::LIB_PATH
16
22
 
17
- attach_function :free, :string_free, [Message], :int32
23
+ attach_function :free, :string_free, [RustString], :int32
18
24
  end
19
25
 
20
26
  private_constant :Rust
data/lib/oso/polar/ffi.rb CHANGED
@@ -4,6 +4,7 @@ require 'ffi'
4
4
 
5
5
  module Oso
6
6
  module Polar
7
+ # FFI classes shared between all ffi/*.rb modules
7
8
  module FFI
8
9
  LIB = "#{::FFI::Platform::LIBPREFIX}polar.#{::FFI::Platform::LIBSUFFIX}"
9
10
  RELEASE_PATH = File.expand_path(File.join(__dir__, "../../../ext/oso-oso/lib/#{LIB}"))
@@ -18,41 +19,50 @@ module Oso
18
19
 
19
20
  # Wrapper class for Polar FFI pointer + operations.
20
21
  class Polar < ::FFI::AutoPointer
22
+ def zero?
23
+ null?
24
+ end
25
+
21
26
  def self.release(ptr)
22
27
  Rust.free(ptr) unless ptr.null?
23
28
  end
24
29
  end
25
30
  # Wrapper class for Query FFI pointer + operations.
26
31
  class Query < ::FFI::AutoPointer
27
- def self.release(ptr)
28
- Rust.free(ptr) unless ptr.null?
32
+ def zero?
33
+ null?
29
34
  end
30
- end
31
- # Wrapper class for QueryEvent FFI pointer + operations.
32
- class QueryEvent < ::FFI::AutoPointer
35
+
33
36
  def self.release(ptr)
34
37
  Rust.free(ptr) unless ptr.null?
35
38
  end
36
39
  end
37
- # Wrapper class for Error FFI pointer + operations.
38
- class Error < ::FFI::AutoPointer
39
- def self.release(ptr)
40
- Rust.free(ptr) unless ptr.null?
40
+
41
+ # Wrapper class for Rust strings FFI pointer + operations.
42
+ class RustString < ::FFI::AutoPointer
43
+ def zero?
44
+ null?
41
45
  end
42
- end
43
- # Wrapper class for Message FFI pointer + operations.
44
- class Message < ::FFI::AutoPointer
46
+
45
47
  def self.release(ptr)
46
48
  Rust.free(ptr) unless ptr.null?
47
49
  end
48
50
  end
49
51
 
50
- # Wrapper class for Source FFI pointer.
51
- class Source < ::FFI::AutoPointer
52
- def self.release(ptr)
53
- Rust.free(ptr) unless ptr.null?
54
- end
52
+ # Helper method to generate a Result type for different
53
+ # inner types
54
+ def self.result(result_klass)
55
+ Class.new(::FFI::Struct) do
56
+ layout :result, result_klass, :error, RustString
57
+ end.by_ref
55
58
  end
59
+
60
+ # Defines the result type version of
61
+ # each of these structs
62
+ # result(T) => { result: T, error: string }
63
+ CResultVoid = result(:int)
64
+ CResultString = result(RustString)
65
+ CResultQuery = result(Query)
56
66
  end
57
67
  private_constant :FFI
58
68
  end
@@ -60,7 +70,5 @@ end
60
70
 
61
71
  require 'oso/polar/ffi/polar'
62
72
  require 'oso/polar/ffi/query'
63
- require 'oso/polar/ffi/query_event'
64
73
  require 'oso/polar/ffi/error'
65
- require 'oso/polar/ffi/message'
66
- require 'oso/polar/ffi/source'
74
+ require 'oso/polar/ffi/rust_string'
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'data'
4
+
3
5
  module Oso
4
6
  module Polar
5
7
  # Ruby code reloaders (i.e. the one used by rails) swap out the value of
@@ -67,7 +69,7 @@ module Oso
67
69
  public
68
70
 
69
71
  attr_writer :accept_expression
70
- attr_accessor :build_query, :combine_query, :exec_query
72
+ attr_accessor :build_query, :combine_query, :exec_query, :adapter
71
73
 
72
74
  DEFAULT_COMBINE_QUERY = proc { raise 'implement combine_query to use data filtering' }
73
75
  DEFAULT_BUILD_QUERY = proc { raise 'implement build_query to use data filtering' }
@@ -95,9 +97,10 @@ module Oso
95
97
  # @return [Class]
96
98
  # @raise [UnregisteredClassError] if the class has not been registered.
97
99
  def get_class(name)
98
- raise UnregisteredClassError, name unless types.key? name
100
+ typ = types[name]
101
+ raise UnregisteredClassError, name if typ.nil?
99
102
 
100
- types[name].klass.get
103
+ typ.klass.get
101
104
  end
102
105
 
103
106
  # Store a Ruby class in the {#types} cache.
@@ -316,8 +319,26 @@ module Oso
316
319
  end
317
320
  else
318
321
  instance_id = nil
319
- instance_id = types[value].id if value.is_a?(Class) && types.key?(value)
320
- { 'ExternalInstance' => { 'instance_id' => cache_instance(value, id: instance_id), 'repr' => nil } }
322
+ class_id = nil
323
+ class_repr = nil
324
+ # id=class_id,
325
+
326
+ # pass `class_id` & `class_repr` for registered types
327
+ if value.is_a?(Class) && types.key?(value)
328
+ instance_id = class_id = types[value].id
329
+ elsif types.key?(value.class)
330
+ class_id = types[value.class].id
331
+ class_repr = types[value.class].name
332
+ end
333
+
334
+ {
335
+ 'ExternalInstance' => {
336
+ 'instance_id' => cache_instance(value, id: instance_id),
337
+ 'repr' => nil,
338
+ 'class_repr' => class_repr,
339
+ 'class_id' => class_id
340
+ }
341
+ }
321
342
  end
322
343
  { 'value' => value }
323
344
  end
@@ -337,21 +358,25 @@ module Oso
337
358
  value
338
359
  when 'Number'
339
360
  num = value.values.first
340
- if value.key? 'Float'
361
+ case value.keys.first
362
+ when 'Float'
341
363
  case num
342
364
  when 'Infinity'
343
- return Float::INFINITY
365
+ Float::INFINITY
344
366
  when '-Infinity'
345
- return -Float::INFINITY
367
+ -Float::INFINITY
346
368
  when 'NaN'
347
- return Float::NAN
369
+ Float::NAN
348
370
  else
349
371
  unless value['Float'].is_a? Float # rubocop:disable Metrics/BlockNesting
350
372
  raise PolarRuntimeError, "Expected a floating point number, got \"#{value['Float']}\""
351
373
  end
374
+
375
+ num
352
376
  end
377
+ else
378
+ num
353
379
  end
354
- num
355
380
  when 'List'
356
381
  value.map { |el| to_ruby(el) }
357
382
  when 'Dictionary'
@@ -84,20 +84,8 @@ module Oso
84
84
  @ffi_polar
85
85
  end
86
86
 
87
- # get the (maybe user-supplied) name of a class.
88
- # kind of a hack because of class autoreloading.
89
- def get_class_name(klass) # rubocop:disable Metrics/AbcSize
90
- if host.types.key? klass
91
- host.types[klass].name
92
- elsif host.types.key? klass.name
93
- host.types[klass.name].name
94
- else
95
- rec = host.types.values.find { |v| v.klass.get == klass }
96
- raise "Unknown class `#{klass}`" if rec.nil?
97
-
98
- host.types[klass] = rec
99
- rec.name
100
- end
87
+ def name_to_class(class_name)
88
+ host.types[class_name].klass.get
101
89
  end
102
90
 
103
91
  # Clear all rules and rule sources from the current Polar instance
@@ -229,6 +217,7 @@ module Oso
229
217
  exec_query: exec_query || maybe_mtd(cls, :exec_query)
230
218
  )
231
219
  register_constant(cls, name: name)
220
+ host.register_mros
232
221
  end
233
222
 
234
223
  # Register a Ruby object with Polar.
@@ -259,10 +248,82 @@ module Oso
259
248
 
260
249
  private
261
250
 
251
+ # new/old data filtering core API shared logic
252
+ def partial_query(actor, action, resource_cls) # rubocop:disable Metrics/MethodLength
253
+ var_name = 'resource'
254
+ resource = Variable.new var_name
255
+
256
+ partials = query_rule(
257
+ 'allow',
258
+ actor,
259
+ action,
260
+ resource,
261
+ bindings: { var_name => type_constraint(resource, resource_cls) },
262
+ accept_expression: true
263
+ )
264
+
265
+ partials.each_with_object([]) do |result, out|
266
+ result.each do |key, val|
267
+ out.push prefilter_isas(key, val)
268
+ end
269
+ end
270
+ end
271
+
272
+ def new_authorized_query(actor, action, resource_class)
273
+ partials = partial_query(actor, action, resource_class)
274
+ types = host.serialize_types
275
+ class_name = class_to_name resource_class
276
+ plan = ffi.build_data_filter(types, partials, 'resource', class_name)
277
+ filter = ::Oso::Polar::Data::Filter.parse(self, plan)
278
+ host.adapter.build_query filter
279
+ end
280
+
281
+ # handle Isa constraints in a partial query
282
+ def prefilter_isas(key, val) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
283
+ # this will usually be the case! sometimes not, if it's an instance.
284
+ if val.is_a?(Expression) && val.operator == 'And'
285
+ # get the isas
286
+ isas, othas = val.args.partition do |expr|
287
+ expr.operator == 'Isa' &&
288
+ expr.args[1].is_a?(Pattern) &&
289
+ expr.args[1].fields.empty?
290
+ end
291
+
292
+ # drop all the isas we can verify now, keep everything else
293
+ othas += isas.reject do |isa|
294
+ isa.args[0].is_a? name_to_class isa.args[1].tag
295
+ end
296
+
297
+ # TODO(gw) check the rest of them instead of just adding them?
298
+ val.args = othas
299
+ end
300
+ val = host.to_polar val
301
+ { 'bindings' => { key => val } }
302
+ end
303
+
304
+ # get the (maybe user-supplied) name of a class.
305
+ # kind of a hack because of class autoreloading.
306
+ def class_to_name(klass) # rubocop:disable Metrics/AbcSize
307
+ if (rec = host.types[klass]) || (rec = host.types[klass.name])
308
+ rec.name
309
+ elsif (rec = host.types.values.find { |v| v.klass.get == klass })
310
+ host.types[klass] = rec
311
+ rec.name
312
+ else
313
+ raise NameError, "Unknown class `#{klass}`"
314
+ end
315
+ end
316
+
317
+ def try_class_to_name(klass)
318
+ class_to_name klass
319
+ rescue NameError
320
+ nil
321
+ end
322
+
262
323
  def type_constraint(var, cls)
263
324
  Expression.new(
264
325
  'And',
265
- [Expression.new('Isa', [var, Pattern.new(get_class_name(cls), {})])]
326
+ [Expression.new('Isa', [var, Pattern.new(class_to_name(cls), {})])]
266
327
  )
267
328
  end
268
329
 
@@ -276,7 +337,6 @@ module Oso
276
337
  # Register MROs, load Polar code, and check inline queries.
277
338
  # @param sources [Array<Source>] Polar sources to load.
278
339
  def load_sources(sources)
279
- host.register_mros
280
340
  ffi_polar.load(sources)
281
341
  check_inline_queries
282
342
  end